Skip to content

Commit b5e32f5

Browse files
committed
Adapt RTSP library to provide TCP transport with interleaved RTP
packets, correct behavior of the CSS class used to hide popup checkboxes
1 parent b8ddd76 commit b5e32f5

8 files changed

Lines changed: 223 additions & 77 deletions

File tree

res/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@
9393
.right { float: right; }
9494
.inline { display: inline-block; }
9595
.nope { display: none; }
96-
.hide { position: absolute; top: -3px; left: -3px; width: 1px; height: 1px; }
96+
.hide { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
9797
.pill { border-radius: 9999px; }
9898
.rounded { border-radius: 4px; }
9999
.scrollx { overflow-x: auto; padding-bottom: .5em; }

src/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ int main(int argc, char *argv[]) {
9696
record_start();
9797

9898
while (keepRunning) {
99+
if (app_config.rtsp_enable) rtsp_tick(rtspHandle);
99100
watchdog_reset();
100101
sleep(1);
101102
}

src/media.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,7 @@ int save_video_stream(char index, hal_vidstream *stream) {
9797
send_h26x_to_client(index, stream);
9898
}
9999
if (app_config.rtsp_enable)
100-
for (int i = 0; i < stream->count; i++)
101-
rtp_send_h26x(rtspHandle, stream->pack[i].data + stream->pack[i].offset,
102-
stream->pack[i].length - stream->pack[i].offset, isH265);
100+
rtp_send_h26x(rtspHandle, stream, isH265);
103101

104102
if (app_config.stream_enable) {
105103
for (int i = 0; i < stream->count; i++) {

src/rtsp/rtcp.h

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "rfc.h"
88
#include "rtsp.h"
99
#include "common.h"
10+
1011
/******************************************************************************
1112
* DECLARATIONS
1213
******************************************************************************/
@@ -20,8 +21,7 @@ static inline int __rtcp_send_sr(struct connection_item_t *con, int track_id);
2021
static inline int __rtcp_send_sr(struct connection_item_t *con, int track_id)
2122
{
2223
struct timeval tv;
23-
unsigned int ts_h;
24-
unsigned int ts_l;
24+
unsigned int ts_h, ts_l;
2525
int send_bytes;
2626
struct sockaddr_in to_addr;
2727
transport_t *t;
@@ -36,21 +36,55 @@ static inline int __rtcp_send_sr(struct connection_item_t *con, int track_id)
3636
ts_h = (unsigned int)tv.tv_sec + 2208988800U;
3737
ts_l = (((double)tv.tv_usec) / 1e6) * 4294967296.0;
3838

39-
rtcp_t rtcp = { common: {version: 2, length: htons(6), p:0, count: 0, pt:RTCP_SR},
39+
rtcp_t rtcp = { common: {version: 2, length: htons(8), p:0, count: 0, pt:RTCP_SR},
4040
r: { sr: { ssrc: htonl(con->ssrc),
4141
ntp_sec: htonl(ts_h),
4242
ntp_frac: htonl(ts_l),
4343
rtp_ts: htonl(t->rtp_timestamp),
4444
psent: htonl(t->rtcp_packet_cnt),
4545
osent: htonl(t->rtcp_octet)}}};
4646

47-
to_addr = con->addr;
48-
to_addr.sin_port = t->client_port_rtcp;
47+
if (t->is_tcp) {
48+
unsigned char head[4];
49+
head[0] = '$';
50+
head[1] = t->channel_rtcp;
51+
head[2] = 0;
52+
head[3] = 36;
53+
54+
pthread_mutex_lock(&con->write_mutex);
55+
int sent_h = 0;
56+
while (sent_h < 4) {
57+
int r = send(con->client_fd, head + sent_h, 4 - sent_h, 0);
58+
if (r > 0) sent_h += r;
59+
else if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) usleep(1000);
60+
else { sent_h = -1; break; }
61+
}
62+
if (sent_h == 4) {
63+
int sent_b = 0;
64+
while (sent_b < 36) {
65+
int r = send(con->client_fd, (char*)&(rtcp) + sent_b, 36 - sent_b, 0);
66+
if (r > 0) sent_b += r;
67+
else if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) usleep(1000);
68+
else { sent_b = -1; break; }
69+
}
70+
send_bytes = sent_b;
71+
} else {
72+
send_bytes = -1;
73+
}
74+
pthread_mutex_unlock(&con->write_mutex);
75+
76+
ASSERT(send_bytes == 36, ({
77+
ERR("send (interleaved):%d:%s\n", send_bytes, strerror(errno));
78+
return FAILURE;}));
79+
} else {
80+
to_addr = con->addr;
81+
to_addr.sin_port = htons(t->client_port_rtcp);
4982

50-
ASSERT((send_bytes = send(t->server_rtcp_fd,
51-
&(rtcp),36,0)) == 36, ({
52-
ERR("send:%d:%s¥n",send_bytes,strerror(errno));
53-
return FAILURE;}));
83+
ASSERT((send_bytes = send(t->server_rtcp_fd,
84+
&(rtcp), 36, 0)) == 36, ({
85+
ERR("send:%d:%s\n", send_bytes, strerror(errno));
86+
return FAILURE;}));
87+
}
5488

5589
t->rtcp_packet_cnt = 0;
5690
t->rtcp_octet = 0;
@@ -59,4 +93,4 @@ static inline int __rtcp_send_sr(struct connection_item_t *con, int track_id)
5993
return SUCCESS;
6094
}
6195

62-
#endif
96+
#endif

src/rtsp/rtp.c

Lines changed: 76 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ static inline int __retrieve_sprop(rtsp_handle h, unsigned char *buf, size_t len
3232
struct __transfer_set_t {
3333
struct list_head_t list_head;
3434
rtsp_handle h;
35+
int track_id;
3536
};
3637

3738
/******************************************************************************
@@ -158,12 +159,11 @@ static inline int __rtp_send_eachconnection(struct list_t *e, void *v)
158159
struct transfer_item_t *trans;
159160
struct nal_rtp_t *rtp = v;
160161
int track_id = rtp->packet.header.pt == 96 ? 0 : 1;
161-
char attempts = 0;
162162

163163
list_upcast(trans,e);
164164

165165
MUST(con = trans->con, return FAILURE);
166-
if (!con->trans[track_id].server_port_rtp) return SUCCESS;
166+
if (!con->trans[track_id].server_port_rtp && !con->trans[track_id].is_tcp) return SUCCESS;
167167

168168
rtp->packet.header.seq = htons(con->trans[track_id].rtp_seq);
169169
if (rtp->packet.header.m)
@@ -172,21 +172,58 @@ static inline int __rtp_send_eachconnection(struct list_t *e, void *v)
172172
rtp->packet.header.ssrc = htonl(con->ssrc);
173173
con->trans[track_id].rtp_seq += 1;
174174

175-
do {
176-
send_bytes = send(con->trans[track_id].server_rtp_fd,
177-
&(rtp->packet),rtp->rtpsize,0);
175+
if (con->trans[track_id].is_tcp) {
176+
unsigned char head[4];
177+
head[0] = '$';
178+
head[1] = con->trans[track_id].channel_rtp;
179+
head[2] = (rtp->rtpsize >> 8) & 0xFF;
180+
head[3] = rtp->rtpsize & 0xFF;
181+
182+
pthread_mutex_lock(&con->write_mutex);
183+
int sent_h = 0;
184+
while (sent_h < 4) {
185+
int r = send(con->client_fd, head + sent_h, 4 - sent_h, 0);
186+
if (r > 0) sent_h += r;
187+
else if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) usleep(1000);
188+
else { sent_h = -1; break; }
189+
}
190+
if (sent_h == 4) {
191+
int sent_b = 0;
192+
while (sent_b < rtp->rtpsize) {
193+
int r = send(con->client_fd, (char*)&(rtp->packet) + sent_b, rtp->rtpsize - sent_b, 0);
194+
if (r > 0) sent_b += r;
195+
else if (r < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) usleep(1000);
196+
else { sent_b = -1; break; }
197+
}
198+
send_bytes = sent_b;
199+
} else {
200+
send_bytes = -1;
201+
}
202+
pthread_mutex_unlock(&con->write_mutex);
178203

179204
if (send_bytes == rtp->rtpsize) {
180205
con->trans[track_id].rtcp_packet_cnt += 1;
181206
con->trans[track_id].rtcp_octet += rtp->rtpsize;
182207
return SUCCESS;
183-
} else if(con->con_state != __CON_S_PLAYING) {
184-
DBG("connection state changed before send\n");
185-
return SUCCESS;
186-
} else
187-
usleep(5000);
188-
} while (++attempts < 10 &&
189-
send_bytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK));
208+
}
209+
} else {
210+
char attempts = 0;
211+
do {
212+
send_bytes = send(con->trans[track_id].server_rtp_fd,
213+
&(rtp->packet),rtp->rtpsize,0);
214+
215+
if (send_bytes == rtp->rtpsize) {
216+
con->trans[track_id].rtcp_packet_cnt += 1;
217+
con->trans[track_id].rtcp_octet += rtp->rtpsize;
218+
return SUCCESS;
219+
} else if(con->con_state != __CON_S_PLAYING) {
220+
DBG("connection state changed before send\n");
221+
return SUCCESS;
222+
} else
223+
usleep(5000);
224+
} while (++attempts < 10 &&
225+
send_bytes == -1 && (errno == EAGAIN || errno == EWOULDBLOCK));
226+
}
190227

191228
ERR("send:%d:%s\n", send_bytes, strerror(errno));
192229
return FAILURE;
@@ -214,7 +251,7 @@ static inline int __rtp_setup_transfer(struct list_t *e, void *v)
214251
if (con->con_state == __CON_S_PLAYING) {
215252

216253
ASSERT(bufpool_get_free(trans_set->h->transfer_pool, &trans) == SUCCESS, ({
217-
ERR("transfer object resouce starvation detected. possibly connection limits are wrongfully setup\n");
254+
ERR("transfer object resource starvation detected. possibly connection limits are wrongfully setup\n");
218255
goto error;}));
219256

220257
MUST(bufpool_attach(con->pool, con) == SUCCESS,
@@ -227,8 +264,8 @@ static inline int __rtp_setup_transfer(struct list_t *e, void *v)
227264

228265
timestamp_offset = trans_set->h->stat.ts_offset;
229266

230-
con->trans[con->track_id].rtp_timestamp =
231-
((unsigned int)con->trans[con->track_id].rtp_timestamp + timestamp_offset);
267+
con->trans[trans_set->track_id].rtp_timestamp =
268+
((unsigned int)con->trans[trans_set->track_id].rtp_timestamp + timestamp_offset);
232269
}
233270

234271
ret = SUCCESS;
@@ -278,8 +315,8 @@ static inline int __retrieve_sprop(rtsp_handle h, unsigned char *buf, size_t len
278315
single_len = 0;
279316

280317
while (__split_nal(buf, &nalptr, &single_len, len) == SUCCESS) {
281-
if ((!(h->isH265) && nalptr[0] & 0x1F == H264_NAL_TYPE_SPS) ||
282-
(h->isH265 && nalptr[0] >> 1 & 0x3F == H265_NAL_TYPE_SPS)) {
318+
if ((!(h->isH265) && (nalptr[0] & 0x1F) == H264_NAL_TYPE_SPS) ||
319+
(h->isH265 && (nalptr[0] >> 1 & 0x3F) == H265_NAL_TYPE_SPS)) {
283320
ASSERT(base64 = mime_base64_create((char *)&(nalptr[0]), single_len), return FAILURE);
284321
ASSERT(base16 = mime_base16_create((char *)&(nalptr[1]), 3), return FAILURE);
285322

@@ -314,8 +351,8 @@ static inline int __retrieve_sprop(rtsp_handle h, unsigned char *buf, size_t len
314351
nalptr = buf;
315352
single_len = 0;
316353
while (__split_nal(buf, &nalptr, &single_len, len) == SUCCESS) {
317-
if ((!(h->isH265) && nalptr[0] & 0x1F == H264_NAL_TYPE_PPS) ||
318-
(h->isH265 && nalptr[0] >> 1 & 0x3F == H265_NAL_TYPE_PPS)) {
354+
if ((!(h->isH265) && (nalptr[0] & 0x1F) == H264_NAL_TYPE_PPS) ||
355+
(h->isH265 && (nalptr[0] >> 1 & 0x3F) == H265_NAL_TYPE_PPS)) {
319356
ASSERT(single_len >= 4, return FAILURE);
320357
ASSERT(base64 = mime_base64_create((char *)&(nalptr[0]), single_len), return FAILURE);
321358

@@ -369,10 +406,8 @@ void rtp_disable_audio(rtsp_handle h)
369406
h->audioPt = 255;
370407
}
371408

372-
int rtp_send_h26x(rtsp_handle h, unsigned char *buf, size_t len, char isH265)
409+
int rtp_send_h26x(rtsp_handle h, hal_vidstream *stream, char isH265)
373410
{
374-
unsigned char *nalptr = buf;
375-
size_t single_len = 0;
376411
int ret = FAILURE;
377412
int track_id = 0;
378413
struct __transfer_set_t trans = {};
@@ -389,16 +424,24 @@ int rtp_send_h26x(rtsp_handle h, unsigned char *buf, size_t len, char isH265)
389424

390425
h->isH265 = isH265;
391426

392-
ASSERT(__retrieve_sprop(h, buf, len) == SUCCESS, goto error);
427+
for (int i = 0; i < stream->count; i++) {
428+
ASSERT(__retrieve_sprop(h, stream->pack[i].data + stream->pack[i].offset,
429+
stream->pack[i].length - stream->pack[i].offset) == SUCCESS, goto error);
430+
}
393431

394432
trans.h = h;
433+
trans.track_id = track_id;
395434

396-
/* setup transmission objecl t*/
397-
ASSERT(list_map_inline(&h->con_list, (__rtp_setup_transfer), &trans) == SUCCESS, goto error);
435+
/* setup transmission object */
436+
rtsp_lock(h);
437+
ASSERT(list_map_inline(&h->con_list, (__rtp_setup_transfer), &trans) == SUCCESS, ({rtsp_unlock(h); goto error;}));
438+
rtsp_unlock(h);
398439

399440
if (trans.list_head.list) {
400-
while (__split_nal(buf, &nalptr, &single_len, len) == SUCCESS) {
401-
ASSERT(__transfer_nal_h26x(&(trans.list_head), nalptr, single_len, h->isH265) == SUCCESS, goto error);
441+
for (int i = 0; i < stream->count; i++) {
442+
ASSERT(__transfer_nal_h26x(&(trans.list_head),
443+
stream->pack[i].data + stream->pack[i].offset,
444+
stream->pack[i].length - stream->pack[i].offset, h->isH265) == SUCCESS, goto error);
402445
}
403446
ASSERT(list_map_inline(&(trans.list_head), (__rtcp_poll), &track_id) == SUCCESS, goto error);
404447
}
@@ -430,9 +473,12 @@ int rtp_send_mp3(rtsp_handle h, unsigned char *buf, size_t len)
430473
h->audioPt = 14;
431474

432475
trans.h = h;
476+
trans.track_id = track_id;
433477

434-
/* setup transmission objecl t*/
435-
ASSERT(list_map_inline(&h->con_list, (__rtp_setup_transfer), &trans) == SUCCESS, goto error);
478+
/* setup transmission object */
479+
rtsp_lock(h);
480+
ASSERT(list_map_inline(&h->con_list, (__rtp_setup_transfer), &trans) == SUCCESS, ({rtsp_unlock(h); goto error;}));
481+
rtsp_unlock(h);
436482

437483
if (trans.list_head.list) {
438484
ASSERT(__transfer_nal_mpga(&(trans.list_head), buf, len) == SUCCESS, goto error);
@@ -445,4 +491,4 @@ int rtp_send_mp3(rtsp_handle h, unsigned char *buf, size_t len)
445491
list_destroy(&(trans.list_head));
446492

447493
return ret;
448-
}
494+
}

0 commit comments

Comments
 (0)