Ejemplo n.º 1
0
void*
rtspserver(void *arg) {
#ifdef WIN32
	SOCKET s = *((SOCKET*) arg);
	int sinlen = sizeof(struct sockaddr_in);
#else
	int s = *((int*) arg);
	socklen_t sinlen = sizeof(struct sockaddr_in);
#endif
	const char *p;
	char buf[8192];
	char cmd[32], url[1024], protocol[32];
	int rlen;
	struct sockaddr_in sin;
	RTSPContext ctx;
	RTSPMessageHeader header1, *header = &header1;
	//int thread_ret;
	// image info
	//int iwidth = video_source_maxwidth(0);
	//int iheight = video_source_maxheight(0);
	//
	rtspconf = rtspconf_global();
	sinlen = sizeof(sin);
	getpeername(s, (struct sockaddr*) &sin, &sinlen);
	//
	bzero(&ctx, sizeof(ctx));
	if(per_client_init(&ctx) < 0) {
		ga_error("server initialization failed.\n");
		return NULL;
	}
	bcopy(&sin, &ctx.client, sizeof(ctx.client));
	ctx.state = SERVER_STATE_IDLE;
	// XXX: hasVideo is used to sync audio/video
	// This value is increased by 1 for each captured frame until it is gerater than zero
	// when this value is greater than zero, audio encoding then starts ...
	//ctx.hasVideo = -(rtspconf->video_fps>>1);	// for slow encoders?
	ctx.hasVideo = 0;	// with 'zerolatency'
	pthread_mutex_init(&ctx.rtsp_writer_mutex, NULL);
	//
	ga_error("[tid %ld] client connected from %s:%d\n",
		ga_gettid(),
		inet_ntoa(sin.sin_addr), htons(sin.sin_port));
	//
	ctx.fd = s;
	//
	do {
		int i, fdmax, active;
		fd_set rfds;
		struct timeval to;
		FD_ZERO(&rfds);
		FD_SET(ctx.fd, &rfds);
		fdmax = ctx.fd;
#ifdef HOLE_PUNCHING
		for(i = 0; i < 2*ctx.streamCount; i++) {
			FD_SET(ctx.rtpSocket[i], &rfds);
			if(ctx.rtpSocket[i] > fdmax)
				fdmax = ctx.rtpSocket[i];
		}
#endif
		to.tv_sec = 0;
		to.tv_usec = 500000;
		if((active = select(fdmax+1, &rfds, NULL, NULL, &to)) < 0) {
			ga_error("select() failed: %s\n", strerror(errno));
			goto quit;
		}
		if(active == 0) {
			// try again!
			continue;
		}
#ifdef HOLE_PUNCHING
		for(i = 0; i < 2*ctx.streamCount; i++) {
			struct sockaddr_in xsin;
#ifdef WIN32
			int xsinlen = sizeof(xsin);
#else
			socklen_t xsinlen = sizeof(xsin);
#endif
			if(FD_ISSET(ctx.rtpSocket[i], &rfds) == 0)
				continue;
			recvfrom(ctx.rtpSocket[i], buf, sizeof(buf), 0,
				(struct sockaddr*) &xsin, &xsinlen);
			if(ctx.rtpPortChecked[i] != 0)
				continue;
			// XXX: port should not flip-flop, so check only once
			if(xsin.sin_addr.s_addr != ctx.client.sin_addr.s_addr) {
				ga_error("RTP: client address mismatched? %u.%u.%u.%u != %u.%u.%u.%u\n",
					NIPQUAD(ctx.client.sin_addr.s_addr),
					NIPQUAD(xsin.sin_addr.s_addr));
				continue;
			}
			if(xsin.sin_port != ctx.rtpPeerPort[i]) {
				ga_error("RTP: client port reconfigured: %u -> %u\n",
					(unsigned int) ntohs(ctx.rtpPeerPort[i]),
					(unsigned int) ntohs(xsin.sin_port));
				ctx.rtpPeerPort[i] = xsin.sin_port;
			} else {
				ga_error("RTP: client is not under an NAT, port %d confirmed\n",
					(int) ntohs(ctx.rtpPeerPort[i]));
			}
			ctx.rtpPortChecked[i] = 1;
		}
		// is RTSP connection?
		if(FD_ISSET(ctx.fd, &rfds) == 0)
			continue;
#endif
		// read commands
		if((rlen = rtsp_getnext(&ctx, buf, sizeof(buf))) < 0) {
			goto quit;
		}
		// Interleaved binary data?
		if(buf[0] == '$') {
			handle_rtcp(&ctx, buf, rlen);
			continue;
		}
		// REQUEST line
		ga_error("%s", buf);
		p = buf;
		get_word(cmd, sizeof(cmd), &p);
		get_word(url, sizeof(url), &p);
		get_word(protocol, sizeof(protocol), &p);
		// check protocol
		if(strcmp(protocol, "RTSP/1.0") != 0) {
			rtsp_reply_error(&ctx, RTSP_STATUS_VERSION);
			goto quit;
		}
		// read headers
		bzero(header, sizeof(*header));
		do {
			int myseq = -1;
			char mysession[sizeof(header->session_id)] = "";
			if((rlen = rtsp_getnext(&ctx, buf, sizeof(buf))) < 0)
				goto quit;
			if(buf[0]=='\n' || (buf[0]=='\r' && buf[1]=='\n'))
				break;
#if 0
			ga_error("HEADER: %s", buf);
#endif
			// Special handling to CSeq & Session header
			// ff_rtsp_parse_line cannot handle CSeq & Session properly on Windows
			// any more?
			if(strncasecmp("CSeq: ", buf, 6) == 0) {
				myseq = strtol(buf+6, NULL, 10);
			}
			if(strncasecmp("Session: ", buf, 9) == 0) {
				strcpy(mysession, buf+9);
			}
			//
			ff_rtsp_parse_line(header, buf, NULL, NULL);
			//
			if(myseq > 0 && header->seq <= 0) {
				ga_error("WARNING: CSeq fixes applied (%d->%d).\n",
					header->seq, myseq);
				header->seq = myseq;
			}
			if(mysession[0] != '\0' && header->session_id[0]=='\0') {
				unsigned i;
				for(i = 0; i < sizeof(header->session_id)-1; i++) {
					if(mysession[i] == '\0'
					|| isspace(mysession[i])
					|| mysession[i] == ';')
						break;
					header->session_id[i] = mysession[i];
				}
				header->session_id[i+1] = '\0';
				ga_error("WARNING: Session fixes applied (%s)\n",
					header->session_id);
			}
		} while(1);
		// special handle to session_id
		if(header->session_id != NULL) {
			char *p = header->session_id;
			while(*p != '\0') {
				if(*p == '\r' || *p == '\n') {
					*p = '\0';
					break;
				}
				p++;
			}
		}
		// handle commands
		ctx.seq = header->seq;
		if (!strcmp(cmd, "DESCRIBE"))
			rtsp_cmd_describe(&ctx, url);
		else if (!strcmp(cmd, "OPTIONS"))
			rtsp_cmd_options(&ctx, url);
		else if (!strcmp(cmd, "SETUP"))
			rtsp_cmd_setup(&ctx, url, header);
		else if (!strcmp(cmd, "PLAY"))
			rtsp_cmd_play(&ctx, url, header);
		else if (!strcmp(cmd, "PAUSE"))
			rtsp_cmd_pause(&ctx, url, header);
		else if (!strcmp(cmd, "TEARDOWN"))
			rtsp_cmd_teardown(&ctx, url, header, 1);
		else
			rtsp_reply_error(&ctx, RTSP_STATUS_METHOD);
		if(ctx.state == SERVER_STATE_TEARDOWN) {
			break;
		}
	} while(1);
quit:
	ctx.state = SERVER_STATE_TEARDOWN;
	//
	close(ctx.fd);
	// 2014-05-20: support only share-encoder model
	ff_server_unregister_client(&ctx);
	//
	per_client_deinit(&ctx);
	//ga_error("RTSP client thread terminated (%d/%d clients left).\n",
	//	video_source_client_count(), audio_source_client_count());
	ga_error("RTSP client thread terminated.\n");
	//
	return NULL;
}
Ejemplo n.º 2
0
void uvc_rtsp_handle(void *param)
{        
	struct stream_context *stream_ctx = (struct stream_context *)param;
        struct rtsp_context *rtsp_ctx;
        u8 *request_header; //buffer to hold rtsp request
        struct sockaddr_in server_addr, client_addr;
	int client_socket;
        socklen_t client_addr_len = sizeof(struct sockaddr_in);
        
        fd_set read_fds;
	struct timeval timeout;
        int ok;
        rtsp_ctx = malloc(sizeof(struct rtsp_context));
        if(rtsp_ctx == NULL)
        {
            RTSP_ERROR("\n\rrtsp context is NULL");
            goto exit;
        }
        request_header = malloc(512);
        if(request_header == NULL)
        {
                RTSP_ERROR("\n\rallocate request header buffer failed");
                goto exit;
        }
        // Delay to wait for IP by DHCP
	vTaskDelay(500);
        	/*init rtsp context to unicast udp mode*/
	if(rtsp_context_init(rtsp_ctx) < 0)
                goto exit;
        
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = *(uint32_t *)(rtsp_ctx->connect_ctx.server_ip)/*htonl(INADDR_ANY)*/;
	server_addr.sin_port = htons(rtsp_ctx->connect_ctx.port);                
		
	if(bind(rtsp_ctx->connect_ctx.socket_id, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
		RTSP_ERROR("\n\rCannot bind stream socket");
		goto exit;
	}
        listen(rtsp_ctx->connect_ctx.socket_id, 1);
        printf("\n\rrtsp context initialized!");      
                
	stream_ctx->protoCtx = (void *)rtsp_ctx;
	rtsp_ctx->stream_ctx = (void *)stream_ctx;
        
        /*start rtp task*/
        uvc_rtp_init(rtsp_ctx);

        
	while(stream_ctx->allowStream)
	{
            FD_ZERO(&read_fds);
            timeout.tv_sec = 1;
            timeout.tv_usec = 0;
            FD_SET(rtsp_ctx->connect_ctx.socket_id, &read_fds);
            if(select(1, &read_fds, NULL, NULL, &timeout))
            {
		client_socket = accept(rtsp_ctx->connect_ctx.socket_id,(struct sockaddr *)&client_addr, &client_addr_len);
		if(client_socket < 0)
		{
			RTSP_ERROR("client_socket error:%d\r\n", client_socket);
			close(client_socket);
			continue;
		}
                *(rtsp_ctx->connect_ctx.remote_ip + 3) = (unsigned char) (client_addr.sin_addr.s_addr >> 24);
                *(rtsp_ctx->connect_ctx.remote_ip + 2) = (unsigned char) (client_addr.sin_addr.s_addr >> 16);
                *(rtsp_ctx->connect_ctx.remote_ip + 1) = (unsigned char) (client_addr.sin_addr.s_addr >> 8);
                *(rtsp_ctx->connect_ctx.remote_ip) = (unsigned char) (client_addr.sin_addr.s_addr );

		while(stream_ctx->allowStream)
		{


                    read(client_socket, request_header, 512);
                    rtsp_readheader(request_header);
                    if(*request_header == 0)
                    {

                            //Do I need to send error response to client?
                            continue;
                    }


                    rtsp_getparam(rtsp_ctx, request_header);
                    switch(rtsp_ctx->rtsp_cmd)
                    {

                            case(CMD_OPTIONS):
                                    RTSP_PRINTF("\n\rReceive options command!");
                                    if(rtsp_ctx->state == RTSP_PLAYING)
                                           break;

                                    rtsp_cmd_options(rtsp_ctx);
                                    ok = write(client_socket, rtsp_ctx->response, strlen(rtsp_ctx->response));
                                    if (ok <= 0)
                                    {


                                           RTSP_ERROR("\n\rsend OPTIONS response failed!");
                                           goto exit;
                                    }
                                    break;



                            case(CMD_DESCRIBE):
                                    RTSP_PRINTF("\n\rReceive describe command!");
                                    if(rtsp_ctx->state == RTSP_PLAYING)
                                           break;

                                    rtsp_cmd_describe(rtsp_ctx);
                                    ok = write(client_socket, rtsp_ctx->response, strlen(rtsp_ctx->response));
                                    if (ok <= 0)
                                    {


                                           RTSP_ERROR("\n\rsend DESCRIBE response failed!");
                                           goto exit;                                                                                                       
                                    }
                                    break;



                            case(CMD_SETUP):
                                    RTSP_PRINTF("\n\rReceive setup command!");
                                    if(rtsp_ctx->state == RTSP_PLAYING)
                                           break;

                                    //fill transport parameter
                                    rtsp_cmd_setup(rtsp_ctx);
                                    ok = write(client_socket, rtsp_ctx->response, strlen(rtsp_ctx->response));
                                    if (ok <= 0)
                                    {


                                           RTSP_ERROR("\n\rsend SETUP response failed!");
                                           goto exit;
                                    }


                                    if(rtsp_ctx->state == RTSP_INIT)
                                    {

                                            rtsp_ctx->state = RTSP_READY;
                                            RTSP_PRINTF("\n\rstate changed from RTSP_INIT to RTSP_READY");
                                    };
                                    break;


                            case(CMD_TEARDOWN):
                                    RTSP_PRINTF("\n\rReceive teardown command!");
                                    rtsp_ctx->state = RTSP_INIT;
                                    rtsp_cmd_teardown(rtsp_ctx);
                                    ok = write(client_socket, rtsp_ctx->response, strlen(rtsp_ctx->response));
                                    if (ok <= 0)
                                    {


                                            RTSP_ERROR("\n\rsend TEARDOWN response failed!");
                                            goto exit;
                                    }
                                    



                                    RTSP_PRINTF("\n\rstreaming teardown, state changed back to RTSP_INIT");
                                    /*have to wait until rtp server reinit*/
                                    vTaskDelay(1000);
                                    goto out;
                                    break;


                            case(CMD_PLAY):
                                    RTSP_PRINTF("\n\rReceive play command!");
                                    if(rtsp_ctx->state == RTSP_PLAYING)
                                           break;

                                    rtsp_cmd_play(rtsp_ctx);
                                    ok = write(client_socket, rtsp_ctx->response, strlen(rtsp_ctx->response));
                                    if (ok <= 0)
                                    {


                                            RTSP_ERROR("\n\rsend PLAY response failed!");
                                            goto exit;
                                    }


                                    if(rtsp_ctx->state == RTSP_READY)
                                    {

                                            rtsp_ctx->state = RTSP_PLAYING;
                                            RTSP_PRINTF("\n\rstate changed from RTSP_READY to RTSP_PLAYING");
                                            rtsp_ctx->is_rtp_start = 1;
                                            RtlUpSema(&rtsp_ctx->start_rtp_sema);
                                    }
                                    break;




                            case(CMD_PAUSE):
                                    RTSP_PRINTF("\n\rReceive pause command!");
                                    rtsp_cmd_pause(rtsp_ctx);
                                    ok = write(client_socket, rtsp_ctx->response, strlen(rtsp_ctx->response));
                                    if (ok <= 0)
                                    {


                                            RTSP_ERROR("\n\rsend PAUSE response failed!");
                                            goto exit;
                                    }


                                    if(rtsp_ctx->state == RTSP_PLAYING)
                                    {

                                            rtsp_ctx->state = RTSP_READY;
                                            RTSP_PRINTF("\n\rstate changed from RTSP_PLAYING to RTSP_READY");
                                    }
                                    break;
                            default:



                                    RTSP_ERROR("\n\rReceive unrecognized command!");
                                    rtsp_cmd_error(rtsp_ctx);
                                    ok = write(client_socket, rtsp_ctx->response, strlen(rtsp_ctx->response));
                                    if (ok <= 0)
                                    {


                                            RTSP_ERROR("\n\rsend ERROR response failed!");
                                            goto exit;
                                    }
                                    rtsp_ctx->state = RTSP_INIT;
                    }
                    if((rtsp_ctx->is_rtp_start == 0) && (rtsp_ctx->state == RTSP_PLAYING))
                    {


                          rtsp_ctx->state = RTSP_INIT;
                          RtlUpSema(&rtsp_ctx->start_rtp_sema);
                    }


		}
out:
                rtsp_ctx->state = RTSP_INIT;
                close(client_socket);                               
            }

	}               
Ejemplo n.º 3
0
bool rtsp_request(t_device_video_play *player)
{
	memset(player->dev_rtsp_info->video_url, 0, 128);
	memset(player->dev_rtsp_info->audio_url, 0, 128);
	memset(player->dev_rtsp_info->session, 0, 64);
	memset(player->dev_rtsp_info->nonce, 0, 64);
	memset(player->dev_rtsp_info->realm, 0, 32);
	player->dev_rtsp_info->cmd_seq = 0;
	player->dev_rtsp_info->secret = false;
	player->dev_rtsp_info->step = enum_cmd_options;
	player->dev_rtsp_info->counter = 0;
	player->dev_rtsp_info->chanel = 0;

	char buffer[MAX_BUF_SIZE] = { 0 };
	int length = 0;
	int result = 0;
	// 超过三次发送失败,退出,返回错误
	int last_step = 0;
	int counter = 0;
	while(true)
	{
		if(last_step == player->dev_rtsp_info->step)
		{
			counter += 1;
			if(counter > 3)
			{
				result = -1;
				break;
			}
		}
		else
		{
			last_step = player->dev_rtsp_info->step;
			counter = 1;
		}

		memset(buffer, 0, MAX_BUF_SIZE);
		switch(player->dev_rtsp_info->step)
		{
			case enum_cmd_options:
				length = rtsp_cmd_options(player->dev_rtsp_info, buffer);
				break;
			case enum_cmd_describe:
				length = rtsp_cmd_describe(player->dev_rtsp_info, buffer);
				break;
			case enum_cmd_setup:
				length = rtsp_cmd_setup(player->dev_rtsp_info, buffer);
				break;
			case enum_cmd_play:
				length = rtsp_cmd_play(player->dev_rtsp_info, buffer);
				break;
			default:
				length = -1;
				break;
		}

		if(length == -1)
		{
			break;
			result = -1;
		}
		else
		{
//			log_info(log_queue, "Send rtsp command message: \n%s", buffer);
			int n = send_rtsp_message(player->sockfd, buffer, length);
			memset(buffer, 0, MAX_BUF_SIZE);
			length = recv_rtsp_message(player->sockfd, buffer, MAX_BUF_SIZE);
//			log_info(log_queue, "Recv rtsp reply message: \n%s", buffer);
	
			switch(player->dev_rtsp_info->step)
			{
				case enum_cmd_options:
					result = rtsp_parse_reply_options(player->dev_rtsp_info, buffer, length);
					break;
				case enum_cmd_describe:
					result = rtsp_parse_reply_describe(player->dev_rtsp_info, buffer, length);
					break;
				case enum_cmd_setup:
					result = rtsp_parse_reply_setup(player->dev_rtsp_info, buffer, length);
					break;
				case enum_cmd_play:
					result = rtsp_parse_reply_play(player->dev_rtsp_info, buffer, length);
					break;
				default:
					result = -1;
					break;
			}

			// result为1时,握手结束
			if(result == 0)
			{
				if(player->dev_rtsp_info->step == enum_cmd_setup)
				{
					player->dev_rtsp_info->counter += 1;
					if(player->dev_rtsp_info->chanel > player->dev_rtsp_info->counter)
					{
						player->dev_rtsp_info->step = enum_cmd_setup;
					}
					else
					{
						player->dev_rtsp_info->step += 1;
					}
				}
				else
				{
					player->dev_rtsp_info->step += 1;
				}
			}
			else if(result == 1)
			{
				if(player->dev_rtsp_info->step == enum_cmd_describe)
				{
				}
				else
				{
					break;
				}
			}
			else
			{
				break;
			}
		}
	}
	
	if(result == 1)
	{
		memcpy(player->vir_rtsp_info->session, player->dev_rtsp_info->session, 64);
		memcpy(player->vir_rtsp_info->ssrc[0], player->dev_rtsp_info->ssrc[0], 16);
		memcpy(player->vir_rtsp_info->ssrc[1], player->dev_rtsp_info->ssrc[1], 16);
		memcpy(player->vir_rtsp_info->username, player->dev_rtsp_info->username, 32);
		memcpy(player->vir_rtsp_info->password, player->dev_rtsp_info->password, 32);
		memcpy(player->vir_rtsp_info->nonce, player->dev_rtsp_info->nonce, 64);
		memcpy(player->vir_rtsp_info->realm, player->dev_rtsp_info->realm, 64);
		for(int i = 0; i < 2; i++)
		{
			player->vir_rtsp_info->seq[i] = player->dev_rtsp_info->seq[i];
			player->vir_rtsp_info->rtptime[i] = player->dev_rtsp_info->rtptime[i];
		}
		for(int i = 0; i < 3; i++)
		{
			player->vir_rtsp_info->info_count[i] = player->dev_rtsp_info->info_count[i];
		}
		memcpy(player->vir_rtsp_info->base_info, player->dev_rtsp_info->base_info, 10 * 128);
		memcpy(player->vir_rtsp_info->video_info, player->dev_rtsp_info->video_info, 10 * 128);
		memcpy(player->vir_rtsp_info->audio_info, player->dev_rtsp_info->audio_info, 10 * 128);

		for(int x = 0; x < player->vir_rtsp_info->info_count[0]; x++)
		{
			if(strcmp(player->vir_rtsp_info->base_info[x], "a=control:") == 0)
			{
				sprintf(player->vir_rtsp_info->base_info[x], "a=control:%s/", player->vir_rtsp_info->rtsp_url);
			}
		}

		for(int x = 0; x < player->vir_rtsp_info->info_count[1]; x++)
		{
			if(strcmp(player->vir_rtsp_info->video_info[x], "a=control:") == 0)
			{
				sprintf(player->vir_rtsp_info->video_info[x], "a=control:%s", player->vir_rtsp_info->video_url);
			}
		}

		for(int x = 0; x < player->vir_rtsp_info->info_count[2]; x++)
		{
			if(strcmp(player->vir_rtsp_info->audio_info[x], "a=control:") == 0)
			{
				sprintf(player->vir_rtsp_info->audio_info[x], "a=control:%s", player->vir_rtsp_info->audio_url);
			}
		}
		player->vir_rtsp_info->chanel = player->dev_rtsp_info->chanel;
		return true;
	}
	return false;
}
Ejemplo n.º 4
0
void*
rtspserver(void *arg) {
#ifdef WIN32
	SOCKET s = *((SOCKET*) arg);
	int sinlen = sizeof(struct sockaddr_in);
#else
	int s = *((int*) arg);
	socklen_t sinlen = sizeof(struct sockaddr_in);
#endif
	const char *p;
	char buf[8192];
	char cmd[32], url[1024], protocol[32];
	int rlen;
	struct sockaddr_in sin;
	RTSPContext ctx;
	RTSPMessageHeader header1, *header = &header1;
	int thread_ret;
	// image info
	int iwidth = video_source_width(0);
	int iheight = video_source_height(0);
	//
	rtspconf = rtspconf_global();
	sinlen = sizeof(sin);
	getpeername(s, (struct sockaddr*) &sin, &sinlen);
	//
	bzero(&ctx, sizeof(ctx));
	if(per_client_init(&ctx) < 0) {
		ga_error("server initialization failed.\n");
		return NULL;
	}
	ctx.state = SERVER_STATE_IDLE;
	// XXX: hasVideo is used to sync audio/video
	// This value is increased by 1 for each captured frame until it is gerater than zero
	// when this value is greater than zero, audio encoding then starts ...
	//ctx.hasVideo = -(rtspconf->video_fps>>1);	// for slow encoders?
	ctx.hasVideo = 0;	// with 'zerolatency'
	pthread_mutex_init(&ctx.rtsp_writer_mutex, NULL);
#if 0
	ctx.audioparam.channels = rtspconf->audio_channels;
	ctx.audioparam.samplerate = rtspconf->audio_samplerate;
	if(rtspconf->audio_device_format == AV_SAMPLE_FMT_S16) {
#ifdef WIN32
#else
		ctx.audioparam.format = SND_PCM_FORMAT_S16_LE;
#endif
		ctx.audioparam.bits_per_sample = 16;
	}
	//
	ga_error("INFO: image: %dx%d; audio: %d ch 16-bit pcm @ %dHz\n",
			iwidth, iheight,
			ctx.audioparam.channels,
			ctx.audioparam.samplerate);
#endif
	//
#if 0
#ifdef WIN32
	if(ga_wasapi_init(&ctx.audioparam) < 0) {
		ga_error("cannot init wasapi.\n");
		return NULL;
	}
#else
	if((ctx.audioparam.handle = ga_alsa_init(&ctx.audioparam.sndlog)) == NULL) {
		ga_error("cannot init alsa.\n");
		return NULL;
	}
	if(ga_alsa_set_param(&ctx.audioparam) < 0) {
		ga_error("cannot set alsa parameter\n");
		return NULL;
	}
#endif
#endif
	//
	ga_error("[tid %ld] client connected from %s:%d\n",
		ga_gettid(),
		inet_ntoa(sin.sin_addr), htons(sin.sin_port));
	//
	ctx.fd = s;
	//
	do {
		fd_set rfds;
		FD_ZERO(&rfds);
		FD_SET(ctx.fd, &rfds);
		if(select(ctx.fd+1, &rfds, NULL, NULL, NULL) <=0) {
			ga_error("select() failed: %s\n", strerror(errno));
			goto quit;
		}
		// read commands
		if((rlen = rtsp_getnext(&ctx, buf, sizeof(buf))) < 0) {
			goto quit;
		}
		// Interleaved binary data?
		if(buf[0] == '$') {
			handle_rtcp(&ctx, buf, rlen);
			continue;
		}
		// REQUEST line
		ga_error("%s", buf);
		p = buf;
		get_word(cmd, sizeof(cmd), &p);
		get_word(url, sizeof(url), &p);
		get_word(protocol, sizeof(protocol), &p);
		// check protocol
		if(strcmp(protocol, "RTSP/1.0") != 0) {
			rtsp_reply_error(&ctx, RTSP_STATUS_VERSION);
			goto quit;
		}
		// read headers
		bzero(header, sizeof(*header));
		do {
			int myseq = -1;
			char mysession[sizeof(header->session_id)] = "";
			if((rlen = rtsp_getnext(&ctx, buf, sizeof(buf))) < 0)
				goto quit;
			if(buf[0]=='\n' || (buf[0]=='\r' && buf[1]=='\n'))
				break;
#if 0
			ga_error("HEADER: %s", buf);
#endif
			// Special handling to CSeq & Session header
			// ff_rtsp_parse_line cannot handle CSeq & Session properly on Windows
			// any more?
			if(strncasecmp("CSeq: ", buf, 6) == 0) {
				myseq = strtol(buf+6, NULL, 10);
			}
			if(strncasecmp("Session: ", buf, 9) == 0) {
				strcpy(mysession, buf+9);
			}
			//
			ff_rtsp_parse_line(header, buf, NULL, NULL);
			//
			if(myseq > 0 && header->seq <= 0) {
				ga_error("WARNING: CSeq fixes applied (%d->%d).\n",
					header->seq, myseq);
				header->seq = myseq;
			}
			if(mysession[0] != '\0' && header->session_id[0]=='\0') {
				unsigned i;
				for(i = 0; i < sizeof(header->session_id)-1; i++) {
					if(mysession[i] == '\0'
					|| isspace(mysession[i])
					|| mysession[i] == ';')
						break;
					header->session_id[i] = mysession[i];
				}
				header->session_id[i+1] = '\0';
				ga_error("WARNING: Session fixes applied (%s)\n",
					header->session_id);
			}
		} while(1);
		// special handle to session_id
		if(header->session_id != NULL) {
			char *p = header->session_id;
			while(*p != '\0') {
				if(*p == '\r' || *p == '\n') {
					*p = '\0';
					break;
				}
				p++;
			}
		}
		// handle commands
		ctx.seq = header->seq;
		if (!strcmp(cmd, "DESCRIBE"))
			rtsp_cmd_describe(&ctx, url);
		else if (!strcmp(cmd, "OPTIONS"))
			rtsp_cmd_options(&ctx, url);
		else if (!strcmp(cmd, "SETUP"))
			rtsp_cmd_setup(&ctx, url, header);
		else if (!strcmp(cmd, "PLAY"))
			rtsp_cmd_play(&ctx, url, header);
		else if (!strcmp(cmd, "PAUSE"))
			rtsp_cmd_pause(&ctx, url, header);
		else if (!strcmp(cmd, "TEARDOWN"))
			rtsp_cmd_teardown(&ctx, url, header);
		else
			rtsp_reply_error(&ctx, RTSP_STATUS_METHOD);
		if(ctx.state == SERVER_STATE_TEARDOWN) {
			break;
		}
	} while(1);
quit:
	ctx.state = SERVER_STATE_TEARDOWN;
	//
	close(ctx.fd);
#ifdef	SHARE_ENCODER
	encoder_unregister_client(&ctx);
#else
	ga_error("connection closed, checking for worker threads...\n");
#if 0
	//
	if(ctx.vthreadId != 0) {
		video_source_notify_one(ctx.vthreadId);
	}
#endif
	pthread_join(ctx.vthread, (void**) &thread_ret);
#ifdef	ENABLE_AUDIO
	pthread_join(ctx.athread, (void**) &thread_ret);
#endif	/* ENABLE_AUDIO */
#endif	/* SHARE_ENCODER */
	//
	per_client_deinit(&ctx);
	//ga_error("RTSP client thread terminated (%d/%d clients left).\n",
	//	video_source_client_count(), audio_source_client_count());
	ga_error("RTSP client thread terminated.\n");
	//
	return NULL;
}
Ejemplo n.º 5
0
static int rtsp_parse_request(RTSPContext *c)
{
    const char *p, *p1, *p2;
    char cmd[32];
    char url[1024];
    char protocol[32];
    char line[1024];
    int len;
    RTSPMessageHeader header1 = { 0 }, *header = &header1;

    c->buffer_ptr[0] = '\0';
    p = c->buffer;

    get_word(cmd, sizeof(cmd), &p);
    get_word(url, sizeof(url), &p);
    get_word(protocol, sizeof(protocol), &p);

    av_strlcpy(c->method, cmd, sizeof(c->method));
    av_strlcpy(c->url, url, sizeof(c->url));
    av_strlcpy(c->protocol, protocol, sizeof(c->protocol));

    if (avio_open_dyn_buf(&c->pb) < 0) {
       //  XXX: cannot do more 
        c->pb = NULL;//  safety 
        return -1;
    }

    printf("cmd = %s \n", cmd);
    /* check version name */
    if (strcmp(protocol, "RTSP/1.0") != 0) {
        rtsp_reply_error(c, RTSP_STATUS_VERSION);
        goto the_end;
    }
    /* parse each header line */
    /* skip to next line */
    while (*p != '\n' && *p != '\0')
        p++;
    if (*p == '\n')
        p++;
    while (*p != '\0') {
      p1 = memchr(p, '\n', (char *)c->buffer_ptr - p);
      if (!p1)
          break;
      p2 = p1;
      if (p2 > p && p2[-1] == '\r')
          p2--;
      /* skip empty line */
      if (p2 == p)
          break;
      len = p2 - p;
      if (len > sizeof(line) - 1)
          len = sizeof(line) - 1;
      memcpy(line, p, len);
      line[len] = '\0';
      //printf("rstp_parse_line = %s\n", line);
      // range parsing! 
      if (!strncmp(line, "Range: npt=", strlen("Range: npt="))) {
        printf("range info contained! line = %s \n", line);
        char *end_pos = strrchr(line, '-');
        char *start_pos = strrchr(line, '=');
        char *start_npt = malloc(end_pos - start_pos - 1);
        strncpy(start_npt, start_pos+1, end_pos - start_pos - 1);
        //printf("range start npt = %s\n", start_npt);
        double start_time = 0.0;
        sscanf(start_npt, "%lf", &start_time);
        //printf("range start time = %lfs\n", start_time);
        c->ntp_start_time = start_time;
      }

      // for trick
      if (!strncmp(line, "Scale:", strlen("Scale:"))) {
        printf("scale info contained! line = %s \n", line);
        char *end_pos = strrchr(line, '\n');
        char *start_pos = strrchr(line, ' ');
        char *scale = malloc(end_pos - start_pos - 1);
        strncpy(scale, start_pos+1, end_pos - start_pos - 1);
        printf("scale = %s\n", scale);
        double speed = 0.0;
        sscanf(scale, "%lf", &speed);
      }
      ff_rtsp_parse_line(header, line, NULL, NULL);
      p = p1 + 1;
    }
    /* handle sequence number */
    c->seq = header->seq;
    if (!strcmp(cmd, "DESCRIBE")) {
        printf("DESCRIBE!!!\n");
        rtsp_cmd_describe(c, url);
    }
    else if (!strcmp(cmd, "OPTIONS")) {
        printf("Options! \n");
        rtsp_cmd_options(c, url);
    }
    else if (!strcmp(cmd, "SETUP")) {
        printf("Setup!!!\n");
        rtsp_cmd_setup(c, url, header);
    }
    else if (!strcmp(cmd, "PLAY")) {
        printf("Play!!! \n");
        rtsp_cmd_play(c, url, header);
    }
    else if (!strcmp(cmd, "PAUSE")) {
        printf("PAUSE!!!\n");
        rtsp_cmd_interrupt(c, url, header, 1);
    }
    else if (!strcmp(cmd, "TEARDOWN")) {
        rtsp_cmd_interrupt(c, url, header, 0);
        printf("TEARDOWN!!!\n");
    }
    else {
        rtsp_reply_error(c, RTSP_STATUS_METHOD);
        printf("Error!!");
    }

 the_end:
    // write rstp reply packet! text 
    len = avio_close_dyn_buf(c->pb, &c->pb_buffer);
    c->pb = NULL; /* safety */
    if (len < 0) {
      /* XXX: cannot do more */
      printf("error! len < 0 when avio close dyn buf");
        return -1;
    }
    c->buffer_ptr = c->pb_buffer;
    c->buffer_end = c->pb_buffer + len;
    c->state = RTSPSTATE_SEND_REPLY;
    return 0;
}