@@ -73,7 +73,6 @@ public class Decoder extends Activity {
7373 private final BlockingQueue <Frame > pcmQueue = new ArrayBlockingQueue <>(32 );
7474 private final byte [] nalBuffer = new byte [1024 * 1024 ];
7575
76- // volatile: these fields are read/written from multiple threads
7776 private int nalSize ; // only touched on the network thread — no volatile needed
7877 private volatile MediaCodec mDecoder ;
7978 private SurfaceView mSurface ;
@@ -855,6 +854,27 @@ private void parseSdpAudioRate(String sdp) {
855854 }
856855 }
857856
857+ /**
858+ * Parses per-track Control URLs from an SDP body (RFC 2326 §C.1.1).
859+ * Returns a 2-element array: [videoControlUrl, audioControlUrl].
860+ * Absolute "a=control:" values are used as-is; relative values are resolved
861+ * against {@code baseUrl}. Falls back to "{@code baseUrl}/trackID=N" if absent.
862+ */
863+ private static String [] parseSdpControls (String sdp , String baseUrl ) {
864+ String [] controls = { baseUrl + "/trackID=0" , baseUrl + "/trackID=1" };
865+ int track = -1 ;
866+ for (String line : sdp .split ("[\r \n ]+" )) {
867+ if (line .startsWith ("m=video" )) track = 0 ;
868+ else if (line .startsWith ("m=audio" )) track = 1 ;
869+ else if (line .startsWith ("a=control:" ) && track >= 0 ) {
870+ String ctrl = line .substring ("a=control:" .length ()).trim ();
871+ // absolute URL used as-is; relative URL appended to base
872+ controls [track ] = ctrl .startsWith ("rtsp://" ) ? ctrl : baseUrl + "/" + ctrl ;
873+ }
874+ }
875+ return controls ;
876+ }
877+
858878 private void rtspConnect () throws Exception {
859879 nalSize = 0 ; // discard any partial NAL fragment from the previous session
860880 Uri uri = Uri .parse (mHost );
@@ -910,11 +930,13 @@ private void rtspConnect() throws Exception {
910930 sdpBodyLen -= n ;
911931 }
912932 parseSdpAudioRate (sdp .toString ());
933+ // parse per-track Control URLs; used for SETUP requests below
934+ String [] trackUrls = parseSdpControls (sdp .toString (), rtspUrl );
913935
914936 seq ++;
915937 String type = mType ? "RTP/AVP/UDP;unicast;client_port=5000"
916938 : "RTP/AVP/TCP;unicast;interleaved=0-1" ;
917- String video = "SETUP " + rtspUrl + "/trackID=0 RTSP/1.0\r \n " +
939+ String video = "SETUP " + trackUrls [ 0 ] + " RTSP/1.0\r \n " +
918940 "CSeq: " + seq + "\r \n " + auth + UA + "Transport: " + type + "\r \n \r \n " ;
919941 w .write (video .getBytes (StandardCharsets .UTF_8 ));
920942 w .flush ();
@@ -930,7 +952,7 @@ private void rtspConnect() throws Exception {
930952 seq ++;
931953 type = mType ? "RTP/AVP/UDP;unicast;client_port=5002"
932954 : "RTP/AVP/TCP;unicast;interleaved=2-3" ;
933- String audio = "SETUP " + rtspUrl + "/trackID=1 RTSP/1.0\r \n " +
955+ String audio = "SETUP " + trackUrls [ 1 ] + " RTSP/1.0\r \n " +
934956 "CSeq: " + seq + "\r \n " + auth + UA + "Transport: " + type + "\r \n " +
935957 "Session: " + session + "\r \n \r \n " ;
936958 w .write (audio .getBytes (StandardCharsets .UTF_8 ));
@@ -1107,7 +1129,10 @@ private void startListener() {
11071129 if (!activeStream ) {
11081130 runOnUiThread (() -> mConnect .setVisibility (View .VISIBLE ));
11091131 rtspConnect ();
1110- retryDelay = 1000 ; // reset on successful connection
1132+ retryDelay = 1000 ; // reset backoff after any successful session
1133+ // brief pause before reconnecting after a clean server-side close;
1134+ // without this the loop hammers the camera with no delay
1135+ SystemClock .sleep (1000 );
11111136 }
11121137 } catch (Exception e ) {
11131138 Log .w (TAG , "Cannot connect rtsp: " + e .getMessage ());
0 commit comments