📄 rtsp_session.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / IETF RTP/RTSP/SDP sub-project * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/internal/ietf_dev.h>#include <gpac/base_coding.h>#ifdef _WIN32_WCE#define RTSP_TRACE 0#else#define RTSP_TRACE 1#endifGF_Err RTSP_UnpackURL(char *sURL, char *Server, u16 *Port, char *Service, Bool *useTCP){ char schema[10], *test, text[1024], *retest; u32 i, len; Bool is_ipv6; if (!sURL) return GF_BAD_PARAM; strcpy(Server, ""); strcpy(Service, ""); *Port = *useTCP =0; if (!strchr(sURL, ':')) return GF_BAD_PARAM; //extract the schema i = 0; while (i<=strlen(sURL)) { if (sURL[i] == ':') goto found; schema[i] = sURL[i]; i += 1; } return GF_BAD_PARAM;found: schema[i] = 0; if (stricmp(schema, "rtsp") && stricmp(schema, "rtspu")) return GF_URL_ERROR; //check for user/pass - not allowed/* test = strstr(sURL, "@"); if (test) return GF_NOT_SUPPORTED;*/ test = strstr(sURL, "://"); if (!test) return GF_URL_ERROR; test += 3; //check for service retest = strstr(test, "/"); if (!retest) return GF_URL_ERROR; if (!stricmp(schema, "rtsp")) *useTCP = 1; //check for port retest = strrchr(test, ':'); /*IPV6 address*/ if (retest && strchr(retest, ']')) retest = NULL; if (retest && strstr(retest, "/")) { retest += 1; i=0; while (i<strlen(retest)) { if (retest[i] == '/') break; text[i] = retest[i]; i += 1; } text[i] = 0; *Port = atoi(text); } //get the server name is_ipv6 = 0; len = strlen(test); i=0; while (i<len) { if (test[i]=='[') is_ipv6 = 1; else if (test[i]==']') is_ipv6 = 0; if ( (test[i] == '/') || (!is_ipv6 && (test[i] == ':')) ) break; text[i] = test[i]; i += 1; } text[i] = 0; strcpy(Server, text); while (test[i] != '/') i += 1; strcpy(Service, test+i+1); return GF_OK;}//create a new GF_RTSPSession from URL - DO NOT USE WITH SDPGF_EXPORTGF_RTSPSession *gf_rtsp_session_new(char *sURL, u16 DefaultPort){ GF_RTSPSession *sess; char server[1024], service[1024]; GF_Err e; u16 Port; Bool UseTCP; if (!sURL) return NULL; e = RTSP_UnpackURL(sURL, server, &Port, service, &UseTCP); if (e) return NULL; GF_SAFEALLOC(sess, GF_RTSPSession); sess->ConnectionType = UseTCP ? GF_SOCK_TYPE_TCP : GF_SOCK_TYPE_UDP; if (Port) sess->Port = Port; else if (DefaultPort) sess->Port = DefaultPort; else sess->Port = 554; //HTTP tunnel if (sess->Port == 80) { sess->ConnectionType = GF_SOCK_TYPE_TCP; sess->HasTunnel = 1; } sess->Server = strdup(server); sess->Service = strdup(service); sess->mx = gf_mx_new(); sess->TCPChannels = gf_list_new(); gf_rtsp_session_reset(sess, 0); return sess;}GF_EXPORTvoid gf_rtsp_reset_aggregation(GF_RTSPSession *sess){ if (!sess) return; gf_mx_p(sess->mx); if (sess->RTSP_State == GF_RTSP_STATE_WAIT_FOR_CONTROL) { strcpy(sess->RTSPLastRequest, "RESET"); //skip all we haven't recieved sess->CSeq += sess->NbPending; sess->NbPending = 0; } sess->RTSP_State = GF_RTSP_STATE_INIT; gf_mx_v(sess->mx);}void RTSP_AcknowledgeError(GF_RTSPSession *sess){}void RemoveTCPChannels(GF_RTSPSession *sess){ GF_TCPChan *ch; while (gf_list_count(sess->TCPChannels)) { ch = (GF_TCPChan*)gf_list_get(sess->TCPChannels, 0); free(ch); gf_list_rem(sess->TCPChannels, 0); }}GF_EXPORTvoid gf_rtsp_session_reset(GF_RTSPSession *sess, Bool ResetConnection){ gf_mx_p(sess->mx); sess->last_session_id = NULL; sess->NeedConnection = 1; if (ResetConnection) { if (sess->connection) gf_sk_del(sess->connection); sess->connection = NULL; if (sess->http) { gf_sk_del(sess->http); sess->http = NULL; } } sess->RTSP_State = GF_RTSP_STATE_INIT;// sess->CSeq = sess->NbPending = 0; sess->InterID = (u8) -1; sess->pck_start = sess->payloadSize = 0; sess->CurrentPos = sess->CurrentSize = 0; strcpy(sess->RTSPLastRequest, ""); RemoveTCPChannels(sess); gf_mx_v(sess->mx);}GF_EXPORTvoid gf_rtsp_session_del(GF_RTSPSession *sess){ if (!sess) return; gf_rtsp_session_reset(sess, 0); if (sess->connection) gf_sk_del(sess->connection); if (sess->http) gf_sk_del(sess->http); if (sess->Server) free(sess->Server); if (sess->Service) free(sess->Service); gf_list_del(sess->TCPChannels); if (sess->rtsp_pck_buf) free(sess->rtsp_pck_buf); gf_mx_del(sess->mx); free(sess);}GF_EXPORTu32 gf_rtsp_get_session_state(GF_RTSPSession *sess){ u32 state; if (!sess) return GF_RTSP_STATE_INVALIDATED; gf_mx_p(sess->mx); state = sess->RTSP_State; gf_mx_v(sess->mx); return state;}GF_EXPORTchar *gf_rtsp_get_last_request(GF_RTSPSession *sess){ char *ret; if (!sess) return NULL; gf_mx_p(sess->mx); ret = sess->RTSPLastRequest; gf_mx_v(sess->mx); return ret;}//check whether the url contains server and service name//no thread protection as this is const throughout the sessionGF_EXPORTu32 gf_rtsp_is_my_session(GF_RTSPSession *sess, char *url){ if (!sess) return 0; if (!strstr(url, sess->Server)) return 0; //same url or sub-url if (strstr(url, sess->Service)) return 1; return 0;}GF_EXPORTconst char *gf_rtsp_get_last_session_id(GF_RTSPSession *sess){ if (!sess) return NULL; return sess->last_session_id;}GF_EXPORTchar *gf_rtsp_get_server_name(GF_RTSPSession *sess){ if (!sess) return NULL; return sess->Server;}GF_EXPORTchar *gf_rtsp_get_service_name(GF_RTSPSession *sess){ if (!sess) return NULL; return sess->Service;}GF_EXPORTu16 gf_rtsp_get_session_port(GF_RTSPSession *sess){ return (sess ? sess->Port : 0);}GF_Err gf_rtsp_check_connection(GF_RTSPSession *sess){ GF_Err e; //active, return if (!sess->NeedConnection) return GF_OK; //socket is destroyed, recreate if (!sess->connection) { sess->connection = gf_sk_new(sess->ConnectionType); if (!sess->connection) return GF_OUT_OF_MEM; } //the session is down, reconnect e = gf_sk_connect(sess->connection, sess->Server, sess->Port); if (e) return e; if (sess->SockBufferSize) gf_sk_set_buffer_size(sess->connection, 0, sess->SockBufferSize); if (!sess->http && sess->HasTunnel) { e = gf_rtsp_http_tunnel_start(sess, "toto is the king of RTSP"); if (e) return e; } sess->NeedConnection = 0; return GF_OK;}GF_Err gf_rtsp_send_data(GF_RTSPSession *sess, char *buffer, u32 Size){ GF_Err e; u32 Size64; e = gf_rtsp_check_connection(sess); if (e) return e; //RTSP requests on HTTP are base 64 encoded if (sess->HasTunnel) { char buf64[3000]; Size64 = gf_base64_encode(buffer, Size, buf64, 3000); buf64[Size64] = 0; //send on http connection return gf_sk_send_wait(sess->http, buf64, Size64, 30); } else { return gf_sk_send(sess->connection, buffer, Size); }}static GF_TCPChan *GetTCPChannel(GF_RTSPSession *sess, u8 rtpID, u8 rtcpID, Bool RemoveIt){ GF_TCPChan *ptr; u32 i, count = gf_list_count(sess->TCPChannels); for (i=0; i<count; i++) { ptr = (GF_TCPChan *)gf_list_get(sess->TCPChannels, i); if (ptr->rtpID == rtpID) goto exit;; if (ptr->rtcpID == rtcpID) goto exit; } return NULL;exit: if (RemoveIt) gf_list_rem(sess->TCPChannels, i); return ptr;}GF_Err gf_rtsp_set_deinterleave(GF_RTSPSession *sess){ GF_TCPChan *ch; Bool IsRTCP; u8 InterID; u16 paySize; u32 res, Size; char *buffer; if (!sess) return GF_SERVICE_ERROR; Size = sess->CurrentSize - sess->CurrentPos; buffer = sess->TCPBuffer + sess->CurrentPos; if (!Size) return GF_IP_NETWORK_EMPTY; //we do not work with just a header -> force a refill if (Size <= 4) return gf_rtsp_refill_buffer(sess); //break if we get RTSP response on the wire if (!strncmp(buffer, "RTSP", 4)) return GF_IP_NETWORK_EMPTY; //new packet if (!sess->pck_start && (buffer[0] == '$')) { InterID = buffer[1]; paySize = ((buffer[2] << 8) & 0xFF00) | (buffer[3] & 0xFF); /*this may be NULL (data fetched after a teardown) - resync and return*/ ch = GetTCPChannel(sess, InterID, InterID, 0); /*then check wether this is a full packet or a split*/ if (paySize <= Size-4) { if (ch) { IsRTCP = (ch->rtcpID == InterID); sess->RTSP_SignalData(sess, ch->ch_ptr, buffer+4, paySize, IsRTCP);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -