2017-10-09 22:11:01 +08:00
/*
2023-12-09 16:23:51 +08:00
* Copyright ( c ) 2016 - present The ZLMediaKit project authors . All Rights Reserved .
2017-09-27 16:20:30 +08:00
*
2023-12-09 16:23:51 +08:00
* This file is part of ZLMediaKit ( https : //github.com/ZLMediaKit/ZLMediaKit).
2017-09-27 16:20:30 +08:00
*
2023-12-09 16:23:51 +08:00
* Use of this source code is governed by MIT - like license that can be found in the
2020-04-04 20:30:09 +08:00
* LICENSE file in the root of the source tree . All contributing project authors
* may be found in the AUTHORS file in the root of the source tree .
2017-09-27 16:20:30 +08:00
*/
2020-04-04 20:30:09 +08:00
2017-04-25 11:35:41 +08:00
# include "RtspPlayer.h"
2023-05-31 09:59:41 +08:00
# include "Common/config.h"
2021-01-31 19:18:17 +08:00
# include "Rtcp/Rtcp.h"
2022-11-29 11:07:13 +08:00
# include "Rtcp/RtcpContext.h"
# include "RtspDemuxer.h"
2023-05-31 09:59:41 +08:00
# include "RtspMediaSource.h"
2022-11-29 11:07:13 +08:00
# include "RtspPlayerImp.h"
2023-05-31 09:59:41 +08:00
# include "Util/MD5.h"
# include "Util/base64.h"
# include <algorithm>
# include <cmath>
# include <iomanip>
# include <set>
2026-04-01 20:42:32 +08:00
# include <cstring>
# include <ctime>
# if defined(_WIN32)
# include "Util/strptime_win.h"
# endif
2022-11-29 11:07:13 +08:00
2018-10-24 17:17:55 +08:00
using namespace toolkit ;
2022-02-02 20:34:50 +08:00
using namespace std ;
2017-04-01 16:35:56 +08:00
2018-10-24 17:17:55 +08:00
namespace mediakit {
2017-04-01 16:35:56 +08:00
2023-05-31 09:59:41 +08:00
enum PlayType { type_play = 0 , type_pause , type_seek , type_speed } ;
2024-05-11 14:38:33 +08:00
enum class BeatType : uint32_t { both = 0 , rtcp , cmd } ;
2019-11-19 15:52:02 +08:00
2023-05-31 09:59:41 +08:00
RtspPlayer : : RtspPlayer ( const EventPoller : : Ptr & poller )
: TcpClient ( poller ) { }
2021-01-17 10:25:00 +08:00
2017-04-01 16:35:56 +08:00
RtspPlayer : : ~ RtspPlayer ( void ) {
2023-06-10 11:04:52 +08:00
DebugL ;
2017-04-01 16:35:56 +08:00
}
2021-01-17 10:25:00 +08:00
2023-05-31 09:59:41 +08:00
void RtspPlayer : : sendTeardown ( ) {
2020-03-20 11:51:24 +08:00
if ( alive ( ) ) {
2023-07-10 10:53:02 +08:00
if ( ! _control_url . empty ( ) ) {
sendRtspRequest ( " TEARDOWN " , _control_url ) ;
2020-12-19 09:20:24 +08:00
}
shutdown ( SockException ( Err_shutdown , " teardown " ) ) ;
2020-03-20 11:51:24 +08:00
}
2021-01-17 10:25:00 +08:00
}
2020-03-20 11:51:24 +08:00
2023-05-31 09:59:41 +08:00
void RtspPlayer : : teardown ( ) {
2021-01-17 10:25:00 +08:00
sendTeardown ( ) ;
2020-05-15 20:15:43 +08:00
_md5_nonce . clear ( ) ;
_realm . clear ( ) ;
_sdp_track . clear ( ) ;
_session_id . clear ( ) ;
_content_base . clear ( ) ;
2020-03-20 11:51:24 +08:00
RtpReceiver : : clear ( ) ;
2021-01-31 19:18:17 +08:00
_rtcp_context . clear ( ) ;
2018-12-14 17:46:12 +08:00
2020-05-15 20:15:43 +08:00
CLEAR_ARR ( _rtp_sock ) ;
CLEAR_ARR ( _rtcp_sock ) ;
_play_check_timer . reset ( ) ;
_rtp_check_timer . reset ( ) ;
_cseq_send = 1 ;
_on_response = nullptr ;
2017-04-01 16:35:56 +08:00
}
2017-08-03 13:55:46 +08:00
2023-05-31 09:59:41 +08:00
void RtspPlayer : : play ( const string & strUrl ) {
2020-03-20 11:51:24 +08:00
RtspUrl url ;
2022-05-08 16:33:33 +08:00
try {
url . parse ( strUrl ) ;
} catch ( std : : exception & ex ) {
onPlayResult_l ( SockException ( Err_other , StrPrinter < < " illegal rtsp url: " < < ex . what ( ) ) , false ) ;
2020-03-20 11:51:24 +08:00
return ;
}
teardown ( ) ;
if ( url . _user . size ( ) ) {
2022-02-02 20:34:50 +08:00
( * this ) [ Client : : kRtspUser ] = url . _user ;
2020-03-20 11:51:24 +08:00
}
if ( url . _passwd . size ( ) ) {
2022-02-02 20:34:50 +08:00
( * this ) [ Client : : kRtspPwd ] = url . _passwd ;
( * this ) [ Client : : kRtspPwdIsMD5 ] = false ;
2020-03-20 11:51:24 +08:00
}
2020-05-15 20:15:43 +08:00
_play_url = url . _url ;
2022-02-02 20:34:50 +08:00
_rtp_type = ( Rtsp : : eRtpType ) ( int ) ( * this ) [ Client : : kRtpType ] ;
2024-05-11 14:38:33 +08:00
_beat_type = ( * this ) [ Client : : kRtspBeatType ] . as < int > ( ) ;
_beat_interval_ms = ( * this ) [ Client : : kBeatIntervalMS ] . as < int > ( ) ;
2024-06-28 12:43:41 +08:00
_speed = ( * this ) [ Client : : kRtspSpeed ] . as < float > ( ) ;
2020-05-15 20:15:43 +08:00
DebugL < < url . _url < < " " < < ( url . _user . size ( ) ? url . _user : " null " ) < < " " < < ( url . _passwd . size ( ) ? url . _passwd : " null " ) < < " " < < _rtp_type ;
2020-03-20 11:51:24 +08:00
2025-09-10 21:51:26 +08:00
weak_ptr < RtspPlayer > weak_self = static_pointer_cast < RtspPlayer > ( shared_from_this ( ) ) ;
2022-02-02 20:34:50 +08:00
float playTimeOutSec = ( * this ) [ Client : : kTimeoutMS ] . as < int > ( ) / 1000.0f ;
2025-09-10 21:51:26 +08:00
_play_check_timer . reset ( new Timer ( playTimeOutSec , [ weak_self ] ( ) {
if ( auto strong_self = weak_self . lock ( ) ) {
strong_self - > onPlayResult_l ( SockException ( Err_timeout , " play rtsp timeout " ) , false ) ;
}
return false ;
} , getPoller ( ) ) ) ;
2020-03-20 11:51:24 +08:00
2025-09-10 21:51:26 +08:00
auto & adapter = ( * this ) [ Client : : kNetAdapter ] ;
if ( ! adapter . empty ( ) ) {
setNetAdapter ( std : : move ( adapter ) ) ;
}
auto & custom_header = ( * this ) [ Client : : kCustomHeader ] ;
if ( ! custom_header . empty ( ) ) {
_custom_header = mediakit : : Parser : : parseArgs ( custom_header ) ;
2020-03-20 11:51:24 +08:00
}
startConnect ( url . _host , url . _port , playTimeOutSec ) ;
2019-03-01 14:23:28 +08:00
}
2020-01-04 12:03:53 +08:00
2023-05-31 09:59:41 +08:00
void RtspPlayer : : onConnect ( const SockException & err ) {
if ( err . getErrCode ( ) ! = Err_success ) {
onPlayResult_l ( err , false ) ;
2020-03-20 11:51:24 +08:00
return ;
}
2020-05-15 09:53:17 +08:00
sendOptions ( ) ;
2017-04-01 16:35:56 +08:00
}
2023-05-31 09:59:41 +08:00
void RtspPlayer : : onRecv ( const Buffer : : Ptr & buf ) {
if ( _benchmark_mode & & ! _play_check_timer ) {
2024-09-19 14:53:50 +08:00
// 在性能测试模式下, 如果rtsp握手完毕后, 不再解析rtp包 [AUTO-TRANSLATED:747b5399]
// In performance test mode, if the RTSP handshake is complete, no RTP packets will be parsed
2020-05-15 20:15:43 +08:00
_rtp_recv_ticker . resetTime ( ) ;
2020-04-08 11:16:09 +08:00
return ;
}
2021-01-31 19:18:17 +08:00
try {
input ( buf - > data ( ) , buf - > size ( ) ) ;
} catch ( exception & e ) {
SockException ex ( Err_other , e . what ( ) ) ;
onPlayResult_l ( ex , ! _play_check_timer ) ;
}
2017-04-01 16:35:56 +08:00
}
2020-04-23 22:22:24 +08:00
2023-04-28 22:03:16 +08:00
void RtspPlayer : : onError ( const SockException & ex ) {
2024-09-19 14:53:50 +08:00
// 定时器_pPlayTimer为空后表明握手结束了 [AUTO-TRANSLATED:06a369c2]
// After the timer _pPlayTimer is empty, it indicates that the handshake is complete
2023-05-31 09:59:41 +08:00
onPlayResult_l ( ex , ! _play_check_timer ) ;
2017-04-01 16:35:56 +08:00
}
2020-04-23 22:22:24 +08:00
2018-07-02 15:43:37 +08:00
// from live555
bool RtspPlayer : : handleAuthenticationFailure ( const string & paramsStr ) {
2023-05-31 09:59:41 +08:00
if ( ! _realm . empty ( ) ) {
2024-09-19 14:53:50 +08:00
// 已经认证过了 [AUTO-TRANSLATED:f2db5f9c]
// It has been authenticated
2018-07-02 15:43:37 +08:00
return false ;
}
2018-07-05 22:05:09 +08:00
char * realm = new char [ paramsStr . size ( ) ] ;
char * nonce = new char [ paramsStr . size ( ) ] ;
char * stale = new char [ paramsStr . size ( ) ] ;
2023-05-31 09:59:41 +08:00
onceToken token ( nullptr , [ & ] ( ) {
2018-07-05 22:05:09 +08:00
delete [ ] realm ;
delete [ ] nonce ;
delete [ ] stale ;
} ) ;
2018-07-02 15:43:37 +08:00
if ( sscanf ( paramsStr . data ( ) , " Digest realm= \" %[^ \" ] \" , nonce= \" %[^ \" ] \" , stale=%[a-zA-Z] " , realm , nonce , stale ) = = 3 ) {
2020-05-15 20:15:43 +08:00
_realm = ( const char * ) realm ;
_md5_nonce = ( const char * ) nonce ;
2018-07-02 15:43:37 +08:00
return true ;
}
if ( sscanf ( paramsStr . data ( ) , " Digest realm= \" %[^ \" ] \" , nonce= \" %[^ \" ] \" " , realm , nonce ) = = 2 ) {
2020-05-15 20:15:43 +08:00
_realm = ( const char * ) realm ;
_md5_nonce = ( const char * ) nonce ;
2018-07-02 15:43:37 +08:00
return true ;
}
if ( sscanf ( paramsStr . data ( ) , " Basic realm= \" %[^ \" ] \" " , realm ) = = 1 ) {
2020-05-15 20:15:43 +08:00
_realm = ( const char * ) realm ;
2018-07-02 15:43:37 +08:00
return true ;
}
return false ;
}
2020-04-23 22:22:24 +08:00
2025-02-19 15:06:11 +08:00
bool RtspPlayer : : handleResponse ( const std : : string & cmd , const Parser & parser , send_method_handler handler ) {
2020-03-20 11:51:24 +08:00
string authInfo = parser [ " WWW-Authenticate " ] ;
2024-09-19 14:53:50 +08:00
// 发送DESCRIBE命令后的回复 [AUTO-TRANSLATED:39629cf0]
// The response after sending the DESCRIBE command
2023-06-10 11:04:52 +08:00
if ( ( parser . status ( ) = = " 401 " ) & & handleAuthenticationFailure ( authInfo ) ) {
2025-02-19 15:06:11 +08:00
( this - > * handler ) ( ) ;
2020-05-19 10:47:46 +08:00
return false ;
2020-03-20 11:51:24 +08:00
}
2023-06-10 11:04:52 +08:00
if ( parser . status ( ) = = " 302 " | | parser . status ( ) = = " 301 " ) {
2020-03-20 11:51:24 +08:00
auto newUrl = parser [ " Location " ] ;
2023-05-31 09:59:41 +08:00
if ( newUrl . empty ( ) ) {
2020-03-20 11:51:24 +08:00
throw std : : runtime_error ( " 未找到Location字段(跳转url) " ) ;
}
play ( newUrl ) ;
2020-05-19 10:47:46 +08:00
return false ;
2020-03-20 11:51:24 +08:00
}
2023-06-10 11:04:52 +08:00
if ( parser . status ( ) ! = " 200 " ) {
throw std : : runtime_error ( StrPrinter < < cmd < < " : " < < parser . status ( ) < < " " < < parser . statusStr ( ) < < endl ) ;
2020-03-20 11:51:24 +08:00
}
2020-05-19 10:47:46 +08:00
return true ;
}
2018-03-20 11:28:13 +08:00
2023-05-31 09:59:41 +08:00
void RtspPlayer : : handleResDESCRIBE ( const Parser & parser ) {
2025-02-19 15:06:11 +08:00
if ( ! handleResponse ( " DESCRIBE " , parser , & RtspPlayer : : sendDescribe ) ) {
2020-05-19 10:47:46 +08:00
return ;
}
_content_base = parser [ " Content-Base " ] ;
2023-05-31 09:59:41 +08:00
if ( _content_base . empty ( ) ) {
2020-05-15 20:15:43 +08:00
_content_base = _play_url ;
2018-03-20 11:28:13 +08:00
}
2020-05-15 20:15:43 +08:00
if ( _content_base . back ( ) = = ' / ' ) {
_content_base . pop_back ( ) ;
2018-03-20 11:28:13 +08:00
}
2024-09-19 14:53:50 +08:00
// 解析sdp [AUTO-TRANSLATED:ed3f07fe]
// Parse SDP
2023-06-10 11:04:52 +08:00
SdpParser sdpParser ( parser . content ( ) ) ;
2022-09-13 16:27:00 +08:00
2026-04-01 20:42:32 +08:00
// 保存 range 信息(从第一个 track 获取)
auto tracks = sdpParser . getAvailableTrack ( ) ;
if ( ! tracks . empty ( ) ) {
auto title_track = sdpParser . getTrack ( TrackTitle ) ;
if ( title_track & & ! title_track - > _range_type . empty ( ) ) {
_range_type = title_track - > _range_type ;
_range_start_str = title_track - > _range_start_str ;
_range_end_str = title_track - > _range_end_str ;
} else if ( ! tracks . empty ( ) & & ! tracks [ 0 ] - > _range_type . empty ( ) ) {
_range_type = tracks [ 0 ] - > _range_type ;
_range_start_str = tracks [ 0 ] - > _range_start_str ;
_range_end_str = tracks [ 0 ] - > _range_end_str ;
}
}
2023-07-10 10:53:02 +08:00
_control_url = sdpParser . getControlUrl ( _content_base ) ;
2022-09-13 16:27:00 +08:00
string sdp ;
auto play_track = ( TrackType ) ( ( int ) ( * this ) [ Client : : kPlayTrack ] - 1 ) ;
if ( play_track ! = TrackInvalid ) {
auto track = sdpParser . getTrack ( play_track ) ;
_sdp_track . emplace_back ( track ) ;
2024-05-01 13:19:47 +08:00
auto title_track = sdpParser . getTrack ( TrackTitle ) ;
sdp = ( title_track ? title_track - > toString ( ) : " " ) + track - > toString ( ) ;
2022-09-13 16:27:00 +08:00
} else {
_sdp_track = sdpParser . getAvailableTrack ( ) ;
sdp = sdpParser . toString ( ) ;
}
2020-05-15 20:15:43 +08:00
if ( _sdp_track . empty ( ) ) {
2020-03-20 11:51:24 +08:00
throw std : : runtime_error ( " 无有效的Sdp Track " ) ;
}
2022-09-13 16:27:00 +08:00
if ( ! onCheckSDP ( sdp ) ) {
2020-03-20 11:51:24 +08:00
throw std : : runtime_error ( " onCheckSDP faied " ) ;
}
2021-01-31 19:56:18 +08:00
_rtcp_context . clear ( ) ;
2021-01-31 19:18:17 +08:00
for ( auto & track : _sdp_track ) {
2023-05-31 09:59:41 +08:00
if ( track - > _pt ! = 0xff ) {
setPayloadType ( _rtcp_context . size ( ) , track - > _pt ) ;
2022-07-17 00:26:07 +08:00
}
2021-10-13 15:06:13 +08:00
_rtcp_context . emplace_back ( std : : make_shared < RtcpContextForRecv > ( ) ) ;
2021-01-31 19:18:17 +08:00
}
2020-03-20 11:51:24 +08:00
sendSetup ( 0 ) ;
2017-04-01 16:35:56 +08:00
}
2019-07-11 12:12:33 +08:00
2024-09-19 14:53:50 +08:00
// 有必要的情况下创建udp端口 [AUTO-TRANSLATED:651202fc]
// Create UDP port if necessary
2023-05-31 09:59:41 +08:00
void RtspPlayer : : createUdpSockIfNecessary ( int track_idx ) {
2020-05-15 20:15:43 +08:00
auto & rtpSockRef = _rtp_sock [ track_idx ] ;
auto & rtcpSockRef = _rtcp_sock [ track_idx ] ;
2020-05-12 10:22:21 +08:00
if ( ! rtpSockRef | | ! rtcpSockRef ) {
2020-09-12 19:03:52 +08:00
std : : pair < Socket : : Ptr , Socket : : Ptr > pr = std : : make_pair ( createSocket ( ) , createSocket ( ) ) ;
makeSockPair ( pr , get_local_ip ( ) ) ;
2020-05-12 10:22:21 +08:00
rtpSockRef = pr . first ;
rtcpSockRef = pr . second ;
2020-03-20 11:51:24 +08:00
}
2019-07-11 12:12:33 +08:00
}
2024-09-19 14:53:50 +08:00
// 发送SETUP命令 [AUTO-TRANSLATED:68a7ca33]
// Send SETUP command
2020-08-01 10:14:42 +08:00
void RtspPlayer : : sendSetup ( unsigned int track_idx ) {
_on_response = std : : bind ( & RtspPlayer : : handleResSETUP , this , placeholders : : _1 , track_idx ) ;
auto & track = _sdp_track [ track_idx ] ;
2021-02-21 21:27:26 +08:00
auto control_url = track - > getControlUrl ( _content_base ) ;
2020-05-15 20:15:43 +08:00
switch ( _rtp_type ) {
2020-03-20 11:51:24 +08:00
case Rtsp : : RTP_TCP : {
2023-05-31 09:59:41 +08:00
sendRtspRequest (
2024-07-05 20:54:06 +08:00
" SETUP " , control_url ,
2025-03-13 16:22:35 +08:00
{ " Transport " , StrPrinter < < " RTP/AVP/TCP;unicast;interleaved= " < < track_idx * 2 < < " - " < < track_idx * 2 + 1 < < " ;mode=play " } ) ;
2023-05-31 09:59:41 +08:00
} break ;
2020-03-20 11:51:24 +08:00
case Rtsp : : RTP_MULTICAST : {
2024-07-05 20:54:06 +08:00
sendRtspRequest ( " SETUP " , control_url , { " Transport " , " RTP/AVP;multicast;mode=play " } ) ;
2023-05-31 09:59:41 +08:00
} break ;
2020-03-20 11:51:24 +08:00
case Rtsp : : RTP_UDP : {
2020-08-01 10:14:42 +08:00
createUdpSockIfNecessary ( track_idx ) ;
2023-05-31 09:59:41 +08:00
sendRtspRequest (
" SETUP " , control_url ,
{ " Transport " ,
2024-07-05 20:54:06 +08:00
StrPrinter < < " RTP/AVP;unicast;client_port= " < < _rtp_sock [ track_idx ] - > get_local_port ( ) < < " - " < < _rtcp_sock [ track_idx ] - > get_local_port ( )
< < " ;mode=play " } ) ;
2023-05-31 09:59:41 +08:00
} break ;
default : break ;
2020-03-20 11:51:24 +08:00
}
2017-04-01 16:35:56 +08:00
}
2020-08-01 10:14:42 +08:00
void RtspPlayer : : handleResSETUP ( const Parser & parser , unsigned int track_idx ) {
2023-06-10 11:04:52 +08:00
if ( parser . status ( ) ! = " 200 " ) {
throw std : : runtime_error ( StrPrinter < < " SETUP: " < < parser . status ( ) < < " " < < parser . statusStr ( ) < < endl ) ;
2020-03-20 11:51:24 +08:00
}
2020-08-01 10:14:42 +08:00
if ( track_idx = = 0 ) {
2020-05-15 20:15:43 +08:00
_session_id = parser [ " Session " ] ;
2020-12-29 12:16:35 +08:00
_session_id . append ( " ; " ) ;
2023-06-10 12:28:49 +08:00
_session_id = findSubString ( _session_id . data ( ) , nullptr , " ; " ) ;
2020-03-20 11:51:24 +08:00
}
auto strTransport = parser [ " Transport " ] ;
2020-12-27 18:11:10 +08:00
if ( strTransport . find ( " TCP " ) ! = string : : npos | | strTransport . find ( " interleaved " ) ! = string : : npos ) {
2020-05-15 20:15:43 +08:00
_rtp_type = Rtsp : : RTP_TCP ;
2020-12-27 18:11:10 +08:00
} else if ( strTransport . find ( " multicast " ) ! = string : : npos ) {
2020-05-15 20:15:43 +08:00
_rtp_type = Rtsp : : RTP_MULTICAST ;
2020-12-27 18:11:10 +08:00
} else {
2020-05-15 20:15:43 +08:00
_rtp_type = Rtsp : : RTP_UDP ;
2020-03-20 11:51:24 +08:00
}
2020-12-27 18:11:10 +08:00
auto transport_map = Parser : : parseArgs ( strTransport , " ; " , " = " ) ;
2020-05-15 20:15:43 +08:00
RtspSplitter : : enableRecvRtp ( _rtp_type = = Rtsp : : RTP_TCP ) ;
2020-12-27 18:11:10 +08:00
string ssrc = transport_map [ " ssrc " ] ;
2023-05-31 09:59:41 +08:00
if ( ! ssrc . empty ( ) ) {
2020-12-27 18:11:10 +08:00
sscanf ( ssrc . data ( ) , " %x " , & _sdp_track [ track_idx ] - > _ssrc ) ;
2023-05-31 09:59:41 +08:00
} else {
2020-12-27 18:11:10 +08:00
_sdp_track [ track_idx ] - > _ssrc = 0 ;
}
2020-03-20 11:51:24 +08:00
2020-12-27 18:11:10 +08:00
if ( _rtp_type = = Rtsp : : RTP_TCP ) {
int interleaved_rtp , interleaved_rtcp ;
sscanf ( transport_map [ " interleaved " ] . data ( ) , " %d-%d " , & interleaved_rtp , & interleaved_rtcp ) ;
_sdp_track [ track_idx ] - > _interleaved = interleaved_rtp ;
} else {
auto port_str = transport_map [ ( _rtp_type = = Rtsp : : RTP_MULTICAST ? " port " : " server_port " ) ] ;
int rtp_port , rtcp_port ;
sscanf ( port_str . data ( ) , " %d-%d " , & rtp_port , & rtcp_port ) ;
2020-08-01 10:14:42 +08:00
auto & pRtpSockRef = _rtp_sock [ track_idx ] ;
auto & pRtcpSockRef = _rtcp_sock [ track_idx ] ;
2018-12-14 17:46:12 +08:00
2020-05-15 20:15:43 +08:00
if ( _rtp_type = = Rtsp : : RTP_MULTICAST ) {
2024-09-19 14:53:50 +08:00
// udp组播 [AUTO-TRANSLATED:ccc90d1f]
// UDP multicast
2023-05-31 09:59:41 +08:00
auto multiAddr = transport_map [ " destination " ] ;
2020-09-12 19:03:52 +08:00
pRtpSockRef = createSocket ( ) ;
2024-09-19 14:53:50 +08:00
// 目前组播仅支持ipv4 [AUTO-TRANSLATED:8215bfd2]
// Currently, multicast only supports IPv4
2022-05-08 00:26:01 +08:00
if ( ! pRtpSockRef - > bindUdpSock ( rtp_port , " 0.0.0.0 " ) ) {
2020-03-20 11:51:24 +08:00
pRtpSockRef . reset ( ) ;
throw std : : runtime_error ( " open udp sock err " ) ;
}
auto fd = pRtpSockRef - > rawFD ( ) ;
2023-05-31 09:59:41 +08:00
if ( - 1 = = SockUtil : : joinMultiAddrFilter ( fd , multiAddr . data ( ) , get_peer_ip ( ) . data ( ) , get_local_ip ( ) . data ( ) ) ) {
SockUtil : : joinMultiAddr ( fd , multiAddr . data ( ) , get_local_ip ( ) . data ( ) ) ;
2020-03-20 11:51:24 +08:00
}
2022-01-14 13:14:30 +08:00
2024-09-19 14:53:50 +08:00
// 设置rtcp发送端口 [AUTO-TRANSLATED:f39b07bd]
// Set RTCP send port
2022-01-14 13:14:30 +08:00
pRtcpSockRef = createSocket ( ) ;
2024-09-19 14:53:50 +08:00
// 目前组播仅支持ipv4 [AUTO-TRANSLATED:8215bfd2]
// Currently, multicast only supports IPv4
2022-05-08 00:26:01 +08:00
if ( ! pRtcpSockRef - > bindUdpSock ( 0 , " 0.0.0.0 " ) ) {
2024-09-19 14:53:50 +08:00
// 分配端口失败 [AUTO-TRANSLATED:59ecd25d]
// Port allocation failed
2022-01-14 13:14:30 +08:00
throw runtime_error ( " open udp socket failed " ) ;
}
2024-09-19 14:53:50 +08:00
// 设置发送地址和发送端口 [AUTO-TRANSLATED:67e1cb6e]
// Set send address and send port
2022-05-08 00:26:01 +08:00
auto dst = SockUtil : : make_sockaddr ( get_peer_ip ( ) . data ( ) , rtcp_port ) ;
pRtcpSockRef - > bindPeerAddr ( ( struct sockaddr * ) & ( dst ) ) ;
2020-03-20 11:51:24 +08:00
} else {
2020-08-01 10:14:42 +08:00
createUdpSockIfNecessary ( track_idx ) ;
2024-09-19 14:53:50 +08:00
// udp单播 [AUTO-TRANSLATED:7d16a875]
// UDP unicast
2022-05-08 00:26:01 +08:00
auto dst = SockUtil : : make_sockaddr ( get_peer_ip ( ) . data ( ) , rtp_port ) ;
pRtpSockRef - > bindPeerAddr ( ( struct sockaddr * ) & ( dst ) ) ;
2024-09-19 14:53:50 +08:00
// 发送rtp打洞包 [AUTO-TRANSLATED:9a79d94f]
// Send RTP hole punching packet
2020-03-20 11:51:24 +08:00
pRtpSockRef - > send ( " \xce \xfa \xed \xfe " , 4 ) ;
2022-05-08 00:26:01 +08:00
dst = SockUtil : : make_sockaddr ( get_peer_ip ( ) . data ( ) , rtcp_port ) ;
2024-09-19 14:53:50 +08:00
// 设置rtcp发送目标, 为后续发送rtcp做准备 [AUTO-TRANSLATED:70929b8e]
// Set RTCP send target, prepare for subsequent RTCP sending
2022-05-08 00:26:01 +08:00
pRtcpSockRef - > bindPeerAddr ( ( struct sockaddr * ) & ( dst ) ) ;
2020-03-20 11:51:24 +08:00
}
2019-05-08 15:08:57 +08:00
2022-05-08 00:26:01 +08:00
auto peer_ip = get_peer_ip ( ) ;
2023-04-28 22:04:38 +08:00
weak_ptr < RtspPlayer > weakSelf = static_pointer_cast < RtspPlayer > ( shared_from_this ( ) ) ;
2024-09-19 14:53:50 +08:00
// 设置rtp over udp接收回调处理函数 [AUTO-TRANSLATED:6e74b593]
// Set RTP over UDP receive callback handler
2023-05-31 09:59:41 +08:00
pRtpSockRef - > setOnRead ( [ peer_ip , track_idx , weakSelf ] ( const Buffer : : Ptr & buf , struct sockaddr * addr , int addr_len ) {
2019-05-08 15:08:57 +08:00
auto strongSelf = weakSelf . lock ( ) ;
if ( ! strongSelf ) {
return ;
}
2022-05-08 00:26:01 +08:00
if ( SockUtil : : inet_ntoa ( addr ) ! = peer_ip ) {
WarnL < < " 收到其他地址的rtp数据: " < < SockUtil : : inet_ntoa ( addr ) ;
2019-05-08 15:08:57 +08:00
return ;
}
2023-05-31 09:59:41 +08:00
strongSelf - > handleOneRtp (
track_idx , strongSelf - > _sdp_track [ track_idx ] - > _type , strongSelf - > _sdp_track [ track_idx ] - > _samplerate , ( uint8_t * ) buf - > data ( ) , buf - > size ( ) ) ;
2019-05-08 15:08:57 +08:00
} ) ;
2023-05-31 09:59:41 +08:00
if ( pRtcpSockRef ) {
2024-09-19 14:53:50 +08:00
// 设置rtcp over udp接收回调处理函数 [AUTO-TRANSLATED:eed55b8e]
// Set RTCP over UDP receive callback handler
2023-05-31 09:59:41 +08:00
pRtcpSockRef - > setOnRead ( [ peer_ip , track_idx , weakSelf ] ( const Buffer : : Ptr & buf , struct sockaddr * addr , int addr_len ) {
2019-05-08 15:08:57 +08:00
auto strongSelf = weakSelf . lock ( ) ;
if ( ! strongSelf ) {
return ;
}
2022-05-08 00:26:01 +08:00
if ( SockUtil : : inet_ntoa ( addr ) ! = peer_ip ) {
WarnL < < " 收到其他地址的rtcp数据: " < < SockUtil : : inet_ntoa ( addr ) ;
2019-05-08 15:08:57 +08:00
return ;
}
2023-05-31 09:59:41 +08:00
strongSelf - > onRtcpPacket ( track_idx , strongSelf - > _sdp_track [ track_idx ] , ( uint8_t * ) buf - > data ( ) , buf - > size ( ) ) ;
2019-05-08 15:08:57 +08:00
} ) ;
}
2020-03-20 11:51:24 +08:00
}
2020-08-01 10:14:42 +08:00
if ( track_idx < _sdp_track . size ( ) - 1 ) {
2024-09-19 14:53:50 +08:00
// 需要继续发送SETUP命令 [AUTO-TRANSLATED:d7ea1a7a]
// Need to continue sending SETUP command
2020-08-01 10:14:42 +08:00
sendSetup ( track_idx + 1 ) ;
2020-03-20 11:51:24 +08:00
return ;
}
2024-09-19 14:53:50 +08:00
// 所有setup命令发送完毕 [AUTO-TRANSLATED:be499080]
// All SETUP commands have been sent
// 发送play命令 [AUTO-TRANSLATED:47a826d1]
// Send PLAY command
2025-09-11 16:52:54 +08:00
if ( _speed = = 0.0f ) {
2024-06-28 12:43:41 +08:00
sendPause ( type_play , 0 ) ;
} else {
sendPause ( type_speed , 0 ) ;
}
2017-04-01 16:35:56 +08:00
}
2018-07-02 15:43:37 +08:00
2019-03-28 11:52:07 +08:00
void RtspPlayer : : sendDescribe ( ) {
2024-09-19 14:53:50 +08:00
// 发送DESCRIBE命令后处理函数:handleResDESCRIBE [AUTO-TRANSLATED:3c2b0ffe]
// Handle the response to the DESCRIBE command: handleResDESCRIBE
2020-05-15 20:15:43 +08:00
_on_response = std : : bind ( & RtspPlayer : : handleResDESCRIBE , this , placeholders : : _1 ) ;
2023-05-31 09:59:41 +08:00
sendRtspRequest ( " DESCRIBE " , _play_url , { " Accept " , " application/sdp " } ) ;
2018-07-02 15:43:37 +08:00
}
2023-05-31 09:59:41 +08:00
void RtspPlayer : : sendOptions ( ) {
_on_response = [ this ] ( const Parser & parser ) {
2025-02-19 15:06:11 +08:00
if ( ! handleResponse ( " OPTIONS " , parser , & RtspPlayer : : sendOptions ) ) {
2020-05-19 10:47:46 +08:00
return ;
2020-05-15 09:53:17 +08:00
}
2024-09-19 14:53:50 +08:00
// 获取服务器支持的命令 [AUTO-TRANSLATED:8a6a12f1]
// Get the commands supported by the server
2020-05-15 09:53:17 +08:00
_supported_cmd . clear ( ) ;
2023-05-31 09:59:41 +08:00
auto public_val = split ( parser [ " Public " ] , " , " ) ;
for ( auto & cmd : public_val ) {
2020-05-15 09:53:17 +08:00
trim ( cmd ) ;
_supported_cmd . emplace ( cmd ) ;
}
2024-09-19 14:53:50 +08:00
// 发送Describe请求, 获取sdp [AUTO-TRANSLATED:f2e291d1]
// Send Describe request to get SDP
2020-05-15 09:53:17 +08:00
sendDescribe ( ) ;
} ;
2020-05-15 20:15:43 +08:00
sendRtspRequest ( " OPTIONS " , _play_url ) ;
2020-05-15 09:53:17 +08:00
}
2023-05-31 09:59:41 +08:00
void RtspPlayer : : sendKeepAlive ( ) {
2026-01-08 20:28:30 +08:00
if ( _play_check_timer )
{
WarnL < < " receive RTP packet before handleResPAUSE " ;
}
_on_keepalive_reponse = [ ] ( const Parser & parser ) { } ;
2023-05-31 09:59:41 +08:00
if ( _supported_cmd . find ( " GET_PARAMETER " ) ! = _supported_cmd . end ( ) ) {
2024-09-19 14:53:50 +08:00
// 支持GET_PARAMETER, 用此命令保活 [AUTO-TRANSLATED:b45cd737]
// Support GET_PARAMETER, use this command to keep alive
2023-07-10 10:53:02 +08:00
sendRtspRequest ( " GET_PARAMETER " , _control_url ) ;
2023-05-31 09:59:41 +08:00
} else {
2024-09-19 14:53:50 +08:00
// 不支持GET_PARAMETER, 用OPTIONS命令保活 [AUTO-TRANSLATED:3391350c]
// Do not support GET_PARAMETER, use OPTIONS command to keep alive
2020-05-15 20:15:43 +08:00
sendRtspRequest ( " OPTIONS " , _play_url ) ;
2020-05-15 09:53:17 +08:00
}
2020-05-09 14:04:08 +08:00
}
2023-05-31 09:59:41 +08:00
void RtspPlayer : : sendPause ( int type , uint32_t seekMS ) {
2020-05-15 20:15:43 +08:00
_on_response = std : : bind ( & RtspPlayer : : handleResPAUSE , this , placeholders : : _1 , type ) ;
2024-09-19 14:53:50 +08:00
// 开启或暂停rtsp [AUTO-TRANSLATED:8ba5b594]
// Start or pause RTSP
2023-05-31 09:59:41 +08:00
switch ( type ) {
2023-07-10 10:53:02 +08:00
case type_pause : sendRtspRequest ( " PAUSE " , _control_url , { } ) ; break ;
2026-04-01 20:42:32 +08:00
case type_play : sendRtspRequest ( " PLAY " , _content_base ) ; break ;
case type_seek : {
std : : string range_header ;
if ( _range_type = = " clock " & & ! _range_start_str . empty ( ) ) {
// clock 格式:需要计算新的时间
// 解析起始时间: 20251123T000000Z
struct tm tm_start ;
const char * start_str = _range_start_str . c_str ( ) ;
if ( strptime ( start_str , " %Y%m%dT%H%M%SZ " , & tm_start ) ! = nullptr ) {
// 转换为 time_t, 加上 seekMS 毫秒
# if defined(_WIN32)
time_t start_time = _mkgmtime ( & tm_start ) ;
# else
time_t start_time = timegm ( & tm_start ) ;
# endif
start_time + = seekMS / 1000 ; // 加上秒数
// 格式化新的时间
struct tm tm_new ;
# if defined(_WIN32)
auto gmtime_ret = gmtime_s ( & tm_new , & start_time ) ;
if ( gmtime_ret = = 0 )
# else
auto gmtime_ret = gmtime_r ( & start_time , & tm_new ) ;
if ( gmtime_ret ! = nullptr )
# endif
{
char new_time [ 32 ] ;
strftime ( new_time , sizeof ( new_time ) , " %Y%m%dT%H%M%SZ " , & tm_new ) ;
// 构建 Range 头
range_header = StrPrinter < < " clock= " < < new_time < < " - " < < _range_end_str ;
} else {
// 解析失败,回退到 npt 格式
range_header = StrPrinter < < " npt= " < < setiosflags ( ios : : fixed ) < < setprecision ( 2 ) < < seekMS / 1000.0 < < " - " ;
}
} else {
// 解析失败,回退到 npt 格式
range_header = StrPrinter < < " npt= " < < setiosflags ( ios : : fixed ) < < setprecision ( 2 ) < < seekMS / 1000.0 < < " - " ;
}
} else {
// npt 格式或其他格式
range_header = StrPrinter < < " npt= " < < setiosflags ( ios : : fixed ) < < setprecision ( 2 ) < < seekMS / 1000.0 < < " - " ;
}
sendRtspRequest ( " PLAY " , _control_url , { " Range " , range_header } ) ;
} break ;
2025-09-11 16:52:54 +08:00
case type_speed : speed ( _speed ) ; break ;
2020-03-20 11:51:24 +08:00
default :
WarnL < < " unknown type : " < < type ;
2020-05-15 20:15:43 +08:00
_on_response = nullptr ;
2020-03-20 11:51:24 +08:00
break ;
}
2017-04-01 16:35:56 +08:00
}
2020-04-23 22:22:24 +08:00
2021-08-09 18:28:43 +08:00
void RtspPlayer : : pause ( bool bPause ) {
sendPause ( bPause ? type_pause : type_seek , getProgressMilliSecond ( ) ) ;
}
2021-08-12 16:07:31 +08:00
void RtspPlayer : : speed ( float speed ) {
2023-07-10 10:53:02 +08:00
sendRtspRequest ( " PLAY " , _control_url , { " Scale " , StrPrinter < < speed } ) ;
2017-04-01 16:35:56 +08:00
}
2026-04-01 20:42:32 +08:00
void RtspPlayer : : seekTo ( uint32_t pos ) {
seekToMilliSecond ( pos * 1000 ) ;
}
2023-05-31 09:59:41 +08:00
void RtspPlayer : : handleResPAUSE ( const Parser & parser , int type ) {
2023-06-10 11:04:52 +08:00
if ( parser . status ( ) ! = " 200 " ) {
2020-03-20 11:51:24 +08:00
switch ( type ) {
2023-06-10 11:04:52 +08:00
case type_pause : WarnL < < " Pause failed: " < < parser . status ( ) < < " " < < parser . statusStr ( ) ; break ;
2020-03-20 11:51:24 +08:00
case type_play :
2023-06-10 11:04:52 +08:00
WarnL < < " Play failed: " < < parser . status ( ) < < " " < < parser . statusStr ( ) ;
2023-07-10 10:53:02 +08:00
onPlayResult_l ( SockException ( Err_other , StrPrinter < < " rtsp play failed: " < < parser . status ( ) < < " " < < parser . statusStr ( ) ) , ! _play_check_timer ) ;
2020-03-20 11:51:24 +08:00
break ;
2023-06-10 11:04:52 +08:00
case type_seek : WarnL < < " Seek failed: " < < parser . status ( ) < < " " < < parser . statusStr ( ) ; break ;
2020-03-20 11:51:24 +08:00
}
return ;
}
if ( type = = type_pause ) {
2024-09-19 14:53:50 +08:00
// 暂停成功! [AUTO-TRANSLATED:782cea77]
// Pause successfully!
2020-05-15 20:15:43 +08:00
_rtp_check_timer . reset ( ) ;
2020-03-20 11:51:24 +08:00
return ;
}
2024-09-19 14:53:50 +08:00
// play或seek成功 [AUTO-TRANSLATED:ba7b0da3]
// Play or seek successfully
2020-03-20 11:51:24 +08:00
uint32_t iSeekTo = 0 ;
2024-09-19 14:53:50 +08:00
// 修正时间轴 [AUTO-TRANSLATED:5ab341f9]
// Correct the timeline
2020-03-20 11:51:24 +08:00
auto strRange = parser [ " Range " ] ;
if ( strRange . size ( ) ) {
2023-06-10 12:28:49 +08:00
auto strStart = findSubString ( strRange . data ( ) , " npt= " , " - " ) ;
2020-03-20 11:51:24 +08:00
if ( strStart = = " now " ) {
strStart = " 0 " ;
}
2021-01-17 18:31:50 +08:00
iSeekTo = ( uint32_t ) ( 1000 * atof ( strStart . data ( ) ) ) ;
2020-03-20 11:51:24 +08:00
DebugL < < " seekTo(ms): " < < iSeekTo ;
}
2020-08-01 10:14:42 +08:00
2023-12-09 16:23:51 +08:00
onPlayResult_l ( SockException ( Err_success , type = = type_seek ? " resume rtsp success " : " rtsp play success " ) , ! _play_check_timer ) ;
2017-04-01 16:35:56 +08:00
}
2018-10-30 10:31:27 +08:00
void RtspPlayer : : onWholeRtspPacket ( Parser & parser ) {
2023-08-20 11:19:57 +08:00
if ( ! start_with ( parser . method ( ) , " RTSP " ) ) {
2024-09-19 14:53:50 +08:00
// 不是rtsp回复, 忽略 [AUTO-TRANSLATED:1dca8f64]
// Not an RTSP response, ignore
2023-08-20 11:19:57 +08:00
WarnL < < " Not rtsp response: " < < parser . method ( ) ;
return ;
}
2018-10-30 10:31:27 +08:00
try {
2020-05-15 20:15:43 +08:00
decltype ( _on_response ) func ;
_on_response . swap ( func ) ;
2026-01-08 20:28:30 +08:00
if ( ! func )
{
_on_keepalive_reponse . swap ( func ) ;
}
2023-05-31 09:59:41 +08:00
if ( func ) {
2020-05-15 20:15:43 +08:00
func ( parser ) ;
2018-10-30 10:31:27 +08:00
}
2023-06-10 11:04:52 +08:00
parser . clear ( ) ;
2018-10-30 10:31:27 +08:00
} catch ( std : : exception & err ) {
2024-09-19 14:53:50 +08:00
// 定时器_pPlayTimer为空后表明握手结束了 [AUTO-TRANSLATED:06a369c2]
// _pPlayTimer is empty after handshake ends
2023-05-31 09:59:41 +08:00
onPlayResult_l ( SockException ( Err_other , err . what ( ) ) , ! _play_check_timer ) ;
2017-04-01 16:35:56 +08:00
}
}
2021-01-17 18:31:50 +08:00
void RtspPlayer : : onRtpPacket ( const char * data , size_t len ) {
2018-10-30 10:31:27 +08:00
int trackIdx = - 1 ;
uint8_t interleaved = data [ 1 ] ;
2023-05-31 09:59:41 +08:00
if ( interleaved % 2 = = 0 ) {
2025-03-13 16:22:35 +08:00
CHECK ( len > RtpPacket : : kRtpHeaderSize + RtpPacket : : kRtpTcpHeaderSize ) ;
RtpHeader * header = ( RtpHeader * ) ( data + RtpPacket : : kRtpTcpHeaderSize ) ;
trackIdx = getTrackIndexByPT ( header - > pt ) ;
2022-06-18 21:19:26 +08:00
if ( trackIdx = = - 1 ) {
return ;
}
2023-05-31 09:59:41 +08:00
handleOneRtp (
trackIdx , _sdp_track [ trackIdx ] - > _type , _sdp_track [ trackIdx ] - > _samplerate , ( uint8_t * ) data + RtpPacket : : kRtpTcpHeaderSize ,
len - RtpPacket : : kRtpTcpHeaderSize ) ;
} else {
2019-05-08 15:08:57 +08:00
trackIdx = getTrackIndexByInterleaved ( interleaved - 1 ) ;
2022-06-18 21:19:26 +08:00
if ( trackIdx = = - 1 ) {
return ;
}
2023-05-31 09:59:41 +08:00
onRtcpPacket ( trackIdx , _sdp_track [ trackIdx ] , ( uint8_t * ) data + RtpPacket : : kRtpTcpHeaderSize , len - RtpPacket : : kRtpTcpHeaderSize ) ;
2018-10-30 10:31:27 +08:00
}
2017-04-01 16:35:56 +08:00
}
2024-09-19 14:53:50 +08:00
// 此处预留rtcp处理函数 [AUTO-TRANSLATED:30c3afa8]
// Reserved for RTCP processing function
2023-05-31 09:59:41 +08:00
void RtspPlayer : : onRtcpPacket ( int track_idx , SdpTrack : : Ptr & track , uint8_t * data , size_t len ) {
auto rtcp_arr = RtcpHeader : : loadFromBytes ( ( char * ) data , len ) ;
2021-01-31 19:18:17 +08:00
for ( auto & rtcp : rtcp_arr ) {
_rtcp_context [ track_idx ] - > onRtcp ( rtcp ) ;
2023-05-31 09:59:41 +08:00
if ( ( RtcpType ) rtcp - > pt = = RtcpType : : RTCP_SR ) {
auto sr = ( RtcpSR * ) ( rtcp ) ;
2024-09-19 14:53:50 +08:00
// 设置rtp时间戳与ntp时间戳的对应关系 [AUTO-TRANSLATED:e92f4749]
// Set the correspondence between RTP timestamp and NTP timestamp
2021-09-02 21:17:59 +08:00
setNtpStamp ( track_idx , sr - > rtpts , sr - > getNtpUnixStampMS ( ) ) ;
2021-07-12 21:18:22 +08:00
}
2019-05-09 13:35:54 +08:00
}
2019-05-08 15:08:57 +08:00
}
2017-04-01 16:35:56 +08:00
2023-05-31 09:59:41 +08:00
void RtspPlayer : : onRtpSorted ( RtpPacket : : Ptr rtppt , int trackidx ) {
2021-01-31 19:19:24 +08:00
_stamp [ trackidx ] = rtppt - > getStampMS ( ) ;
2025-12-01 20:35:54 +08:00
if ( ! _first_stamp [ trackidx ] ) {
_first_stamp [ trackidx ] = _stamp [ trackidx ] ;
}
2021-01-31 19:18:17 +08:00
_rtp_recv_ticker . resetTime ( ) ;
2021-02-05 11:28:50 +08:00
onRecvRTP ( std : : move ( rtppt ) , _sdp_track [ trackidx ] ) ;
2017-04-01 16:35:56 +08:00
}
2020-04-23 22:22:24 +08:00
2023-05-31 09:59:41 +08:00
float RtspPlayer : : getPacketLossRate ( TrackType type ) const {
2021-01-31 19:18:17 +08:00
size_t lost = 0 , expected = 0 ;
2020-08-01 10:14:42 +08:00
try {
auto track_idx = getTrackIndexByTrackType ( type ) ;
2023-08-31 10:53:46 +08:00
if ( _rtcp_context . empty ( ) ) {
return 0 ;
}
2021-01-31 19:18:17 +08:00
auto ctx = _rtcp_context [ track_idx ] ;
lost = ctx - > getLost ( ) ;
expected = ctx - > getExpectedPackets ( ) ;
2020-08-01 10:14:42 +08:00
} catch ( . . . ) {
2021-01-31 19:18:17 +08:00
for ( auto & ctx : _rtcp_context ) {
lost + = ctx - > getLost ( ) ;
expected + = ctx - > getExpectedPackets ( ) ;
2020-03-20 11:51:24 +08:00
}
}
2021-01-31 19:18:17 +08:00
if ( ! expected ) {
return 0 ;
}
2023-05-31 09:59:41 +08:00
return ( float ) ( double ( lost ) / double ( expected ) ) ;
2017-04-01 16:35:56 +08:00
}
2023-05-31 09:59:41 +08:00
uint32_t RtspPlayer : : getProgressMilliSecond ( ) const {
2025-12-01 20:35:54 +08:00
return MAX ( _stamp [ 0 ] - _first_stamp [ 0 ] , _stamp [ 1 ] - _first_stamp [ 1 ] ) ;
2017-04-01 16:35:56 +08:00
}
2020-04-23 22:22:24 +08:00
2018-10-26 14:12:16 +08:00
void RtspPlayer : : seekToMilliSecond ( uint32_t ms ) {
2023-05-31 09:59:41 +08:00
sendPause ( type_seek , ms ) ;
2017-04-01 16:35:56 +08:00
}
2018-07-02 15:43:37 +08:00
2019-03-28 11:52:07 +08:00
void RtspPlayer : : sendRtspRequest ( const string & cmd , const string & url , const std : : initializer_list < string > & header ) {
2020-03-20 11:51:24 +08:00
string key ;
StrCaseMap header_map ;
int i = 0 ;
2023-05-31 09:59:41 +08:00
for ( auto & val : header ) {
if ( + + i % 2 = = 0 ) {
header_map . emplace ( key , val ) ;
} else {
2020-03-20 11:51:24 +08:00
key = val ;
}
}
2023-05-31 09:59:41 +08:00
sendRtspRequest ( cmd , url , header_map ) ;
2018-12-17 13:48:19 +08:00
}
2020-04-23 22:22:24 +08:00
2023-05-31 09:59:41 +08:00
void RtspPlayer : : sendRtspRequest ( const string & cmd , const string & url , const StrCaseMap & header_const ) {
2020-03-20 11:51:24 +08:00
auto header = header_const ;
2022-11-15 20:52:27 +08:00
header . emplace ( " CSeq " , StrPrinter < < _cseq_send + + ) ;
header . emplace ( " User-Agent " , kServerName ) ;
2020-03-20 11:51:24 +08:00
2022-11-15 20:52:27 +08:00
if ( ! _session_id . empty ( ) ) {
2020-05-15 20:15:43 +08:00
header . emplace ( " Session " , _session_id ) ;
2020-03-20 11:51:24 +08:00
}
2022-11-15 20:52:27 +08:00
if ( ! _realm . empty ( ) & & ! ( * this ) [ Client : : kRtspUser ] . empty ( ) ) {
if ( ! _md5_nonce . empty ( ) ) {
2024-09-19 14:53:50 +08:00
// MD5认证 [AUTO-TRANSLATED:0640fa6a]
// MD5 authentication
2020-03-20 11:51:24 +08:00
/*
response计算方法如下 :
RTSP客户端应该使用username + password并计算response如下 :
( 1 ) 当 password为MD5编码 , 则
response = md5 ( password : nonce : md5 ( public_method : url ) ) ;
( 2 ) 当 password为ANSI字符串 , 则
response = md5 ( md5 ( username : realm : password ) : nonce : md5 ( public_method : url ) ) ;
2024-09-19 14:53:50 +08:00
/*
The response calculation method is as follows :
The RTSP client should use username + password and calculate the response as follows :
( 1 ) When password is MD5 encoded , then
response = md5 ( password : nonce : md5 ( public_method : url ) ) ;
( 2 ) When password is ANSI string , then
response = md5 ( md5 ( username : realm : password ) : nonce : md5 ( public_method : url ) ) ;
* [ AUTO - TRANSLATED : 7858 b67d ]
2020-03-20 11:51:24 +08:00
*/
2022-02-02 20:34:50 +08:00
string encrypted_pwd = ( * this ) [ Client : : kRtspPwd ] ;
2022-11-15 20:52:27 +08:00
if ( ! ( * this ) [ Client : : kRtspPwdIsMD5 ] . as < bool > ( ) ) {
2022-02-02 20:34:50 +08:00
encrypted_pwd = MD5 ( ( * this ) [ Client : : kRtspUser ] + " : " + _realm + " : " + encrypted_pwd ) . hexdigest ( ) ;
2020-03-20 11:51:24 +08:00
}
2020-05-15 20:15:43 +08:00
auto response = MD5 ( encrypted_pwd + " : " + _md5_nonce + " : " + MD5 ( cmd + " : " + url ) . hexdigest ( ) ) . hexdigest ( ) ;
2020-03-20 11:51:24 +08:00
_StrPrinter printer ;
printer < < " Digest " ;
2022-02-02 20:34:50 +08:00
printer < < " username= \" " < < ( * this ) [ Client : : kRtspUser ] < < " \" , " ;
2020-05-15 20:15:43 +08:00
printer < < " realm= \" " < < _realm < < " \" , " ;
printer < < " nonce= \" " < < _md5_nonce < < " \" , " ;
2020-03-20 11:51:24 +08:00
printer < < " uri= \" " < < url < < " \" , " ;
printer < < " response= \" " < < response < < " \" " ;
2022-11-15 20:52:27 +08:00
header . emplace ( " Authorization " , printer ) ;
} else if ( ! ( * this ) [ Client : : kRtspPwdIsMD5 ] . as < bool > ( ) ) {
2024-09-19 14:53:50 +08:00
// base64认证 [AUTO-TRANSLATED:06d26447]
// Base64 authentication
2022-11-15 20:52:27 +08:00
auto authStrBase64 = encodeBase64 ( ( * this ) [ Client : : kRtspUser ] + " : " + ( * this ) [ Client : : kRtspPwd ] ) ;
header . emplace ( " Authorization " , StrPrinter < < " Basic " < < authStrBase64 ) ;
2020-03-20 11:51:24 +08:00
}
}
_StrPrinter printer ;
2023-07-10 10:53:02 +08:00
printer < < cmd < < " " < < url < < " RTSP/1.0 \r \n " ;
2023-05-31 09:59:41 +08:00
2023-07-10 10:53:02 +08:00
TraceL < < cmd < < " " < < url ;
2025-12-01 20:35:54 +08:00
2025-09-11 16:52:54 +08:00
if ( cmd = = " PLAY " ) {
2025-12-01 20:35:54 +08:00
// play命令时支持覆盖更新rtsp头, 用于onvif点播等场景
2025-09-11 16:52:54 +08:00
for ( auto & pr : _custom_header ) {
2025-12-01 20:35:54 +08:00
header [ pr . first ] = pr . second ;
2025-09-11 16:52:54 +08:00
}
}
2025-12-01 20:35:54 +08:00
for ( auto & pr : header ) {
printer < < pr . first < < " : " < < pr . second < < " \r \n " ;
}
2020-11-01 03:41:35 +08:00
printer < < " \r \n " ;
SockSender : : send ( std : : move ( printer ) ) ;
2018-07-02 15:43:37 +08:00
}
2023-05-31 09:59:41 +08:00
void RtspPlayer : : onBeforeRtpSorted ( const RtpPacket : : Ptr & rtp , int track_idx ) {
2021-01-31 19:18:17 +08:00
auto & rtcp_ctx = _rtcp_context [ track_idx ] ;
2021-07-12 21:18:22 +08:00
rtcp_ctx - > onRtp ( rtp - > getSeq ( ) , rtp - > getStamp ( ) , rtp - > ntp_stamp , rtp - > sample_rate , rtp - > size ( ) - RtpPacket : : kRtpTcpHeaderSize ) ;
2019-05-09 13:35:54 +08:00
2020-08-01 10:14:42 +08:00
auto & ticker = _rtcp_send_ticker [ track_idx ] ;
2024-05-11 14:38:33 +08:00
if ( ticker . elapsedTime ( ) < _beat_interval_ms ) {
2024-09-19 14:53:50 +08:00
// 心跳时间未到 [AUTO-TRANSLATED:265d4e62]
// Heartbeat time not reached
2021-01-31 19:18:17 +08:00
return ;
}
2024-05-11 14:38:33 +08:00
2024-09-19 14:53:50 +08:00
// 有些rtsp服务器需要rtcp保活, 有些需要发送信令保活; rtcp与rtsp信令轮流心跳, 该特性用于兼容issue:#642 [AUTO-TRANSLATED:a36070c5]
// Some RTSP servers require RTCP keep-alive, some require sending signaling keep-alive; RTCP and RTSP signaling alternate heartbeat, this feature is used to be compatible with issue:#642
2021-01-31 19:18:17 +08:00
auto & rtcp_flag = _send_rtcp [ track_idx ] ;
2024-05-11 14:38:33 +08:00
ticker . resetTime ( ) ;
2021-01-31 19:18:17 +08:00
2024-05-11 14:38:33 +08:00
switch ( ( BeatType ) _beat_type ) {
case BeatType : : cmd : rtcp_flag = false ; break ;
case BeatType : : rtcp : rtcp_flag = true ; break ;
case BeatType : : both :
default : rtcp_flag = ! rtcp_flag ; break ;
}
2021-01-31 19:18:17 +08:00
2024-09-19 14:53:50 +08:00
// 发送信令保活 [AUTO-TRANSLATED:0ef0747e]
// Send signaling keep-alive
2021-01-31 19:18:17 +08:00
if ( ! rtcp_flag ) {
if ( track_idx = = 0 ) {
2024-09-19 14:53:50 +08:00
// 两个track无需同时触发发送信令保活 [AUTO-TRANSLATED:7dde4aec]
// Two tracks do not need to trigger sending signaling keep-alive at the same time
2021-01-31 19:18:17 +08:00
sendKeepAlive ( ) ;
2020-05-15 09:53:17 +08:00
}
2021-01-31 19:18:17 +08:00
return ;
2019-05-09 13:35:54 +08:00
}
2021-01-31 19:18:17 +08:00
2024-09-19 14:53:50 +08:00
// 发送rtcp [AUTO-TRANSLATED:5c7aad87]
// Send RTCP
2021-01-31 19:18:17 +08:00
static auto send_rtcp = [ ] ( RtspPlayer * thiz , int index , Buffer : : Ptr ptr ) {
if ( thiz - > _rtp_type = = Rtsp : : RTP_TCP ) {
auto & track = thiz - > _sdp_track [ index ] ;
2023-05-31 09:59:41 +08:00
thiz - > send ( makeRtpOverTcpPrefix ( ( uint16_t ) ( ptr - > size ( ) ) , track - > _interleaved + 1 ) ) ;
2021-01-31 19:18:17 +08:00
thiz - > send ( std : : move ( ptr ) ) ;
} else {
thiz - > _rtcp_sock [ index ] - > send ( std : : move ( ptr ) ) ;
}
} ;
2021-01-31 19:19:24 +08:00
auto ssrc = rtp - > getSSRC ( ) ;
auto rtcp = rtcp_ctx - > createRtcpRR ( ssrc + 1 , ssrc ) ;
2023-05-31 09:59:41 +08:00
auto rtcp_sdes = RtcpSdes : : create ( { kServerName } ) ;
rtcp_sdes - > chunks . type = ( uint8_t ) SdesType : : RTCP_SDES_CNAME ;
2021-07-15 17:38:04 +08:00
rtcp_sdes - > chunks . ssrc = htonl ( ssrc ) ;
2021-01-31 19:18:17 +08:00
send_rtcp ( this , track_idx , std : : move ( rtcp ) ) ;
send_rtcp ( this , track_idx , RtcpHeader : : toBuffer ( rtcp_sdes ) ) ;
2018-07-02 15:43:37 +08:00
}
2020-04-23 22:22:24 +08:00
2023-05-31 09:59:41 +08:00
void RtspPlayer : : onPlayResult_l ( const SockException & ex , bool handshake_done ) {
2020-08-30 10:48:34 +08:00
if ( ex . getErrCode ( ) = = Err_shutdown ) {
2024-09-19 14:53:50 +08:00
// 主动shutdown的, 不触发回调 [AUTO-TRANSLATED:21f9c396]
// Active shutdown, do not trigger callback
2020-08-30 10:48:34 +08:00
return ;
2019-05-08 15:27:37 +08:00
}
2020-08-30 10:48:34 +08:00
WarnL < < ex . getErrCode ( ) < < " " < < ex . what ( ) ;
2020-08-30 11:40:03 +08:00
if ( ! handshake_done ) {
2024-09-19 14:53:50 +08:00
// 开始播放阶段 [AUTO-TRANSLATED:7ef385fc]
// Start playback stage
2020-05-15 20:15:43 +08:00
_play_check_timer . reset ( ) ;
2019-05-08 15:27:37 +08:00
onPlayResult ( ex ) ;
2024-09-19 14:53:50 +08:00
// 是否为性能测试模式 [AUTO-TRANSLATED:871a0e65]
// Whether it is performance test mode
2020-04-08 11:16:09 +08:00
_benchmark_mode = ( * this ) [ Client : : kBenchmarkMode ] . as < int > ( ) ;
2019-11-19 15:52:02 +08:00
} else if ( ex ) {
2024-09-19 14:53:50 +08:00
// 播放成功后异常断开回调 [AUTO-TRANSLATED:3fe28e4f]
// Callback for abnormal disconnection after successful playback
2019-11-19 15:52:02 +08:00
onShutdown ( ex ) ;
} else {
2024-09-19 14:53:50 +08:00
// 恢复播放 [AUTO-TRANSLATED:7a99afd6]
// Resume playback
2019-11-19 15:52:02 +08:00
onResume ( ) ;
2019-05-08 15:27:37 +08:00
}
2020-08-30 10:48:34 +08:00
if ( ! ex ) {
2024-09-19 14:53:50 +08:00
// 播放成功, 恢复rtp接收超时定时器 [AUTO-TRANSLATED:0ebefcb5]
// Playback successful, restore RTP receive timeout timer
2020-08-30 10:48:34 +08:00
_rtp_recv_ticker . resetTime ( ) ;
2022-02-02 20:34:50 +08:00
auto timeoutMS = ( * this ) [ Client : : kMediaTimeoutMS ] . as < uint64_t > ( ) ;
2023-04-28 22:04:38 +08:00
weak_ptr < RtspPlayer > weakSelf = static_pointer_cast < RtspPlayer > ( shared_from_this ( ) ) ;
2020-08-30 10:48:34 +08:00
auto lam = [ weakSelf , timeoutMS ] ( ) {
auto strongSelf = weakSelf . lock ( ) ;
if ( ! strongSelf ) {
return false ;
}
if ( strongSelf - > _rtp_recv_ticker . elapsedTime ( ) > timeoutMS ) {
2024-09-19 14:53:50 +08:00
// 接收rtp媒体数据包超时 [AUTO-TRANSLATED:601b8c0c]
// Receive RTP media data packet timeout
2020-08-30 10:48:34 +08:00
strongSelf - > onPlayResult_l ( SockException ( Err_timeout , " receive rtp timeout " ) , true ) ;
return false ;
}
return true ;
} ;
2024-09-19 14:53:50 +08:00
// 创建rtp数据接收超时检测定时器 [AUTO-TRANSLATED:edbffc19]
// Create RTP data receive timeout detection timer
2025-05-02 16:23:25 +08:00
_rtp_check_timer = std : : make_shared < Timer > ( timeoutMS / 2000.0f , std : : move ( lam ) , getPoller ( ) ) ;
2020-08-30 10:48:34 +08:00
} else {
2021-01-17 10:25:00 +08:00
sendTeardown ( ) ;
2019-05-08 15:27:37 +08:00
}
2018-07-02 15:43:37 +08:00
}
2025-03-13 16:22:35 +08:00
int RtspPlayer : : getTrackIndexByPT ( int pt ) const {
for ( size_t i = 0 ; i < _sdp_track . size ( ) ; + + i ) {
if ( _sdp_track [ i ] - > _pt = = pt ) {
return i ;
}
}
if ( _sdp_track . size ( ) = = 1 ) {
return 0 ;
}
WarnL < < " no such track with pt: " < < pt ;
return - 1 ;
}
2020-05-15 20:15:43 +08:00
int RtspPlayer : : getTrackIndexByInterleaved ( int interleaved ) const {
2022-01-12 15:21:33 +08:00
for ( size_t i = 0 ; i < _sdp_track . size ( ) ; + + i ) {
2020-05-15 20:15:43 +08:00
if ( _sdp_track [ i ] - > _interleaved = = interleaved ) {
2020-03-20 11:51:24 +08:00
return i ;
}
}
2020-05-15 20:15:43 +08:00
if ( _sdp_track . size ( ) = = 1 ) {
2020-03-20 11:51:24 +08:00
return 0 ;
}
2022-06-18 21:19:26 +08:00
WarnL < < " no such track with interleaved: " < < interleaved ;
return - 1 ;
2018-07-05 18:48:08 +08:00
}
2020-08-01 10:14:42 +08:00
int RtspPlayer : : getTrackIndexByTrackType ( TrackType track_type ) const {
2022-01-12 15:21:33 +08:00
for ( size_t i = 0 ; i < _sdp_track . size ( ) ; + + i ) {
2020-08-01 10:14:42 +08:00
if ( _sdp_track [ i ] - > _type = = track_type ) {
2020-03-20 11:51:24 +08:00
return i ;
}
}
2020-05-15 20:15:43 +08:00
if ( _sdp_track . size ( ) = = 1 ) {
2020-03-20 11:51:24 +08:00
return 0 ;
}
2023-07-10 10:53:02 +08:00
throw SockException ( Err_other , StrPrinter < < " no such track with type: " < < getTrackString ( track_type ) ) ;
2018-07-02 15:43:37 +08:00
}
2025-05-02 16:23:25 +08:00
size_t RtspPlayer : : getRecvSpeed ( ) {
size_t ret = TcpClient : : getRecvSpeed ( ) ;
for ( auto & rtp : _rtp_sock ) {
if ( rtp ) {
ret + = rtp - > getRecvSpeed ( ) ;
}
}
for ( auto & rtcp : _rtcp_sock ) {
if ( rtcp ) {
ret + = rtcp - > getRecvSpeed ( ) ;
}
}
return ret ;
}
size_t RtspPlayer : : getRecvTotalBytes ( ) {
size_t ret = TcpClient : : getRecvTotalBytes ( ) ;
for ( auto & rtp : _rtp_sock ) {
if ( rtp ) {
ret + = rtp - > getRecvTotalBytes ( ) ;
}
}
for ( auto & rtcp : _rtcp_sock ) {
if ( rtcp ) {
ret + = rtcp - > getRecvTotalBytes ( ) ;
}
}
return ret ;
}
2022-11-29 11:07:13 +08:00
///////////////////////////////////////////////////
// RtspPlayerImp
2023-05-31 09:59:41 +08:00
float RtspPlayerImp : : getDuration ( ) const {
2022-11-29 11:07:13 +08:00
return _demuxer ? _demuxer - > getDuration ( ) : 0 ;
}
void RtspPlayerImp : : onPlayResult ( const toolkit : : SockException & ex ) {
if ( ! ( * this ) [ Client : : kWaitTrackReady ] . as < bool > ( ) | | ex ) {
Super : : onPlayResult ( ex ) ;
return ;
}
}
void RtspPlayerImp : : addTrackCompleted ( ) {
if ( ( * this ) [ Client : : kWaitTrackReady ] . as < bool > ( ) ) {
Super : : onPlayResult ( toolkit : : SockException ( toolkit : : Err_success , " play success " ) ) ;
}
}
2023-05-31 09:59:41 +08:00
std : : vector < Track : : Ptr > RtspPlayerImp : : getTracks ( bool ready /*= true*/ ) const {
2022-11-29 11:07:13 +08:00
return _demuxer ? _demuxer - > getTracks ( ready ) : Super : : getTracks ( ready ) ;
}
2023-05-31 09:59:41 +08:00
bool RtspPlayerImp : : onCheckSDP ( const std : : string & sdp ) {
2022-11-29 11:07:13 +08:00
_rtsp_media_src = std : : dynamic_pointer_cast < RtspMediaSource > ( _media_src ) ;
if ( _rtsp_media_src ) {
_rtsp_media_src - > setSdp ( sdp ) ;
}
_demuxer = std : : make_shared < RtspDemuxer > ( ) ;
_demuxer - > setTrackListener ( this , ( * this ) [ Client : : kWaitTrackReady ] . as < bool > ( ) ) ;
_demuxer - > loadSdp ( sdp ) ;
return true ;
}
void RtspPlayerImp : : onRecvRTP ( RtpPacket : : Ptr rtp , const SdpTrack : : Ptr & track ) {
2024-09-19 14:53:50 +08:00
// rtp解复用时可以判断是否为关键帧起始位置 [AUTO-TRANSLATED:fb7d9b6e]
// When demultiplexing RTP, it can be determined whether it is the starting position of the key frame
2022-11-29 11:07:13 +08:00
auto key_pos = _demuxer - > inputRtp ( rtp ) ;
if ( _rtsp_media_src ) {
_rtsp_media_src - > onWrite ( std : : move ( rtp ) , key_pos ) ;
}
}
2018-10-24 17:17:55 +08:00
} /* namespace mediakit */