Example #1
0
static void
rtsp_cmd_pause(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) {
	char path[4096];
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	if(strcmp(ctx->session_id, h->session_id) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	//
	if(ctx->state != SERVER_STATE_PLAYING) {
		rtsp_reply_error(ctx, RTSP_STATUS_STATE);
		return;
	}
	//
	ctx->state = SERVER_STATE_PAUSE;
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id);
	rtsp_printf(ctx, "\r\n");
	return;
}
Example #2
0
static void
rtsp_cmd_describe(RTSPContext *ctx, const char *url) {
	struct sockaddr_in myaddr;
#ifdef WIN32
	int addrlen;
#else
	socklen_t addrlen;
#endif
	char path[4096];
	char content[4096];
	int content_length;
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	if(strcmp(path, rtspconf->object) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SERVICE);
		return;
	}
	//
	addrlen = sizeof(myaddr);
	getsockname(ctx->fd, (struct sockaddr*) &myaddr, &addrlen);
	content_length = prepare_sdp_description(ctx, content, sizeof(content));
	if(content_length < 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL);
		return;
	}
	// state does not change
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Content-Base: %s/\r\n", url);
	rtsp_printf(ctx, "Content-Type: application/sdp\r\n");
	rtsp_printf(ctx, "Content-Length: %d\r\n", content_length);
	rtsp_printf(ctx, "\r\n");
	rtsp_write(ctx, content, content_length);
	return;
}
Example #3
0
static void
rtsp_cmd_play(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) {
	char path[4096];
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	if(strcmp(ctx->session_id, h->session_id) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	//
	if(ctx->state != SERVER_STATE_READY
	&& ctx->state != SERVER_STATE_PAUSE) {
		rtsp_reply_error(ctx, RTSP_STATUS_STATE);
		return;
	}
	// 2014-05-20: support only shared-encoder model
	if(ff_server_register_client(ctx) < 0) {
		ga_error("cannot register encoder client.\n");
		rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL);
		return;
	}
	//
	ctx->state = SERVER_STATE_PLAYING;
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id);
	rtsp_printf(ctx, "\r\n");
	return;
}
static void
rtsp_reply_header(RTSPContext *c, enum RTSPStatusCode error_number) {
	const char *str;
	time_t ti;
	struct tm rtm;
	char buf2[32];

	switch(error_number) {
	case RTSP_STATUS_OK:
		str = "OK";
		break;
	case RTSP_STATUS_METHOD:
		str = "Method Not Allowed";
		break;
	case RTSP_STATUS_BANDWIDTH:
		str = "Not Enough Bandwidth";
		break;
	case RTSP_STATUS_SESSION:
		str = "Session Not Found";
		break;
	case RTSP_STATUS_STATE:
		str = "Method Not Valid in This State";
		break;
	case RTSP_STATUS_AGGREGATE:
		str = "Aggregate operation not allowed";
		break;
	case RTSP_STATUS_ONLY_AGGREGATE:
		str = "Only aggregate operation allowed";
		break;
	case RTSP_STATUS_TRANSPORT:
		str = "Unsupported transport";
		break;
	case RTSP_STATUS_INTERNAL:
		str = "Internal Server Error";
		break;
	case RTSP_STATUS_SERVICE:
		str = "Service Unavailable";
		break;
	case RTSP_STATUS_VERSION:
		str = "RTSP Version not supported";
		break;
	default:
		str = "Unknown Error";
		break;
	}

	rtsp_printf(c, "RTSP/1.0 %d %s\r\n", error_number, str);
	rtsp_printf(c, "CSeq: %d\r\n", c->seq);
	/* output GMT time */
	ti = time(NULL);
#ifdef MSYS
	gmtime_s(&rtm, &ti);
#else
	gmtime_r(&ti, &rtm);
#endif
	strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", &rtm);
	rtsp_printf(c, "Date: %s GMT\r\n", buf2);
	//
	return;
}
Example #5
0
static void
rtsp_cmd_options(RTSPContext *c, const char *url) {
	// state does not change
	rtsp_printf(c, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK");
	rtsp_printf(c, "CSeq: %d\r\n", c->seq);
	//rtsp_printf(c, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE");
	rtsp_printf(c, "Public: %s\r\n", "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY");
	rtsp_printf(c, "\r\n");
	return;
}
Example #6
0
static void
rtsp_cmd_play(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) {
	char path[4096];
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	if(strcmp(ctx->session_id, h->session_id) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	//
	if(ctx->state != SERVER_STATE_READY
	&& ctx->state != SERVER_STATE_PAUSE) {
		rtsp_reply_error(ctx, RTSP_STATUS_STATE);
		return;
	}
	// create threads
#ifndef SHARE_ENCODER
	if(pthread_create(&ctx->vthread, NULL, vencoder_thread, ctx) != 0) {
		ga_error("cannot create video thread\n");
		rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL);
		return;
	}
#ifdef ENABLE_AUDIO
	if(pthread_create(&ctx->athread, NULL, aencoder_thread, ctx) != 0) {
		ga_error("cannot create audio thread\n");
		rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL);
		return;
	}
#endif	/* ENABLE_AUDIO */
#else
	if(encoder_register_client(ctx) < 0) {
		ga_error("cannot register encoder client.\n");
		rtsp_reply_error(ctx, RTSP_STATUS_INTERNAL);
		return;
	}
#endif	/* SHARE_ENCODER */
	//
	ctx->state = SERVER_STATE_PLAYING;
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id);
	rtsp_printf(ctx, "\r\n");
	return;
}
Example #7
0
static void
rtsp_cmd_teardown(RTSPContext *ctx, const char *url, RTSPMessageHeader *h, int bruteforce) {
	char path[4096];
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	if(strncmp(path, rtspconf->object, strlen(rtspconf->object)) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	if(strcmp(ctx->session_id, h->session_id) != 0) {
		rtsp_reply_error(ctx, RTSP_STATUS_SESSION);
		return;
	}
	//
	ctx->state = SERVER_STATE_TEARDOWN;
	if(bruteforce != 0)
		return;
	// XXX: well, gently response
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id);
	rtsp_printf(ctx, "\r\n");
	return;
}
Example #8
0
static void
rtsp_cmd_setup(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) {
	int i;
	RTSPTransportField *th;
	struct sockaddr_in destaddr, myaddr;
#ifdef WIN32
	int destaddrlen, myaddrlen;
#else
	socklen_t destaddrlen, myaddrlen;
#endif
	char path[4096];
	char channelname[VIDEO_SOURCE_CHANNEL_MAX+1][RTSP_STREAM_FORMAT_MAXLEN];
	int baselen = strlen(rtspconf->object);
	int streamid;
	int rtp_port, rtcp_port;
	enum RTSPStatusCode errcode;
	//
	av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url);
	for(i = 0; i < VIDEO_SOURCE_CHANNEL_MAX+1; i++) {
		snprintf(channelname[i], RTSP_STREAM_FORMAT_MAXLEN, RTSP_STREAM_FORMAT, i);
	}
	//
	if(strncmp(path, rtspconf->object, baselen) != 0) {
		ga_error("invalid object (path=%s)\n", path);
		rtsp_reply_error(ctx, RTSP_STATUS_AGGREGATE);
		return;
	}
	for(i = 0; i < VIDEO_SOURCE_CHANNEL_MAX+1; i++) {
		if(strcmp(path+baselen+1, channelname[i]) == 0) {
			streamid = i;
			break;
		}
	}
	if(i == VIDEO_SOURCE_CHANNEL_MAX+1) {
		// not found
		ga_error("invalid service (path=%s)\n", path);
		rtsp_reply_error(ctx, RTSP_STATUS_SERVICE);
		return;
	}
	//
	if(ctx->state != SERVER_STATE_IDLE
	&& ctx->state != SERVER_STATE_READY) {
		rtsp_reply_error(ctx, RTSP_STATUS_STATE);
		return;
	}
	// create session id?
	if(ctx->session_id == NULL) {
		if(h->session_id[0] == '\0') {
			snprintf(h->session_id, sizeof(h->session_id), "%04x%04x",
				rand()%0x0ffff, rand()%0x0ffff);
			ctx->session_id = strdup(h->session_id);
			ga_error("New session created (id = %s)\n", ctx->session_id);
		}
	}
	// session id must match -- we have only one session
	if(ctx->session_id == NULL
	|| strcmp(ctx->session_id, h->session_id) != 0) {
		ga_error("Bad session id %s != %s\n", h->session_id, ctx->session_id);
		errcode = RTSP_STATUS_SESSION;
		goto error_setup;
	}
	// find supported transport
	if((th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP)) == NULL) {
		th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP);
	}
	if(th == NULL) {
		ga_error("Cannot find transport\n");
		errcode = RTSP_STATUS_TRANSPORT;
		goto error_setup;
	}
	//
	destaddrlen = sizeof(destaddr);
	bzero(&destaddr, destaddrlen);
	if(getpeername(ctx->fd, (struct sockaddr*) &destaddr, &destaddrlen) < 0) {
		ga_error("Cannot get peername\n");
		errcode = RTSP_STATUS_INTERNAL;
		goto error_setup;
	}
	destaddr.sin_port = htons(th->client_port_min);
	//
	myaddrlen = sizeof(myaddr);
	bzero(&myaddr, myaddrlen);
	if(getsockname(ctx->fd, (struct sockaddr*) &myaddr, &myaddrlen) < 0) {
		ga_error("Cannot get sockname\n");
		errcode = RTSP_STATUS_INTERNAL;
		goto error_setup;
	}
	//
	ctx->lower_transport[streamid] = th->lower_transport;
	if(rtp_new_av_stream(ctx, &destaddr, streamid,
			streamid == video_source_channels()/*rtspconf->audio_id*/ ?
				rtspconf->audio_encoder_codec->id : rtspconf->video_encoder_codec->id) < 0) {
		ga_error("Create AV stream %d failed.\n", streamid);
		errcode = RTSP_STATUS_TRANSPORT;
		goto error_setup;
	}
	//
	ctx->state = SERVER_STATE_READY;
	rtsp_reply_header(ctx, RTSP_STATUS_OK);
	rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id);
	switch(th->lower_transport) {
	case RTSP_LOWER_TRANSPORT_UDP:
#ifdef HOLE_PUNCHING
		rtp_port = ctx->rtpLocalPort[streamid*2];
		rtcp_port = ctx->rtpLocalPort[streamid*2+1];
		ctx->rtpPeerPort[streamid*2] = htons(th->client_port_min);
		ctx->rtpPeerPort[streamid*2+1] = htons(th->client_port_max);
#else
		rtp_port = ff_rtp_get_local_rtp_port((URLContext*) ctx->fmtctx[streamid]->pb->opaque);
		rtcp_port = ff_rtp_get_local_rtcp_port((URLContext*) ctx->fmtctx[streamid]->pb->opaque);
#endif
		ga_error("RTP/UDP: streamid=%d; client=%d-%d; server=%d-%d\n",
			streamid,
			th->client_port_min, th->client_port_max,
			rtp_port, rtcp_port);
		rtsp_printf(ctx, "Transport: RTP/AVP/UDP;unicast;client_port=%d-%d;server_port=%d-%d\r\n",
		       th->client_port_min, th->client_port_max,
		       rtp_port, rtcp_port);
		break;
	case RTSP_LOWER_TRANSPORT_TCP:
		ga_error("RTP/TCP: interleaved=%d-%d\n",
			streamid*2, streamid*2+1);
		rtsp_printf(ctx, "Transport: RTP/AVP/TCP;unicast;interleaved=%d-%d\r\n",
			streamid*2, streamid*2+1, streamid*2);
		break;
	default:
		// should not happen
		break;
	}
	rtsp_printf(ctx, "\r\n");
	return;
error_setup:
	if(ctx->session_id != NULL) {
		free(ctx->session_id);
		ctx->session_id = NULL;
	}
	if(ctx->encoder[streamid] != NULL) {
		ctx->encoder[streamid] = NULL;
	}
	if(ctx->stream[streamid] != NULL) {
		ctx->stream[streamid] = NULL;
	}
	if(ctx->fmtctx[streamid] != NULL) {
		avformat_free_context(ctx->fmtctx[streamid]);
		ctx->fmtctx[streamid] = NULL;
	}
	rtsp_reply_error(ctx, errcode);
	return;
}
Example #9
0
static void
rtsp_reply_error(RTSPContext *c, enum RTSPStatusCode error_number) {
	rtsp_reply_header(c, error_number);
	rtsp_printf(c, "\r\n");
}