Example #1
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);                               
            }

	}               
Example #2
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;
}
Example #3
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;
}