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; }
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); } }
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; }
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; }
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; }