Move RTSP common code from SAT>IP to the common place
This commit is contained in:
parent
a3ad55f64c
commit
a57f86f07b
7 changed files with 337 additions and 521 deletions
1
Makefile
1
Makefile
|
@ -114,6 +114,7 @@ SRCS = src/version.c \
|
||||||
src/service_mapper.c \
|
src/service_mapper.c \
|
||||||
src/input.c \
|
src/input.c \
|
||||||
src/httpc.c \
|
src/httpc.c \
|
||||||
|
src/rtsp.c \
|
||||||
src/fsmonitor.c \
|
src/fsmonitor.c \
|
||||||
src/cron.c \
|
src/cron.c \
|
||||||
|
|
||||||
|
|
60
src/http.h
60
src/http.h
|
@ -84,7 +84,8 @@ typedef enum http_state {
|
||||||
HTTP_CON_SENT,
|
HTTP_CON_SENT,
|
||||||
HTTP_CON_RECEIVING,
|
HTTP_CON_RECEIVING,
|
||||||
HTTP_CON_DONE,
|
HTTP_CON_DONE,
|
||||||
HTTP_CON_IDLE
|
HTTP_CON_IDLE,
|
||||||
|
HTTP_CON_OK
|
||||||
} http_state_t;
|
} http_state_t;
|
||||||
|
|
||||||
typedef enum http_cmd {
|
typedef enum http_cmd {
|
||||||
|
@ -265,6 +266,13 @@ struct http_client {
|
||||||
|
|
||||||
int hc_cseq; /* RTSP */
|
int hc_cseq; /* RTSP */
|
||||||
int hc_rcseq; /* RTSP - expected cseq */
|
int hc_rcseq; /* RTSP - expected cseq */
|
||||||
|
char *hc_rtsp_session;
|
||||||
|
char *hc_rtp_dest;
|
||||||
|
int hc_rtp_port;
|
||||||
|
int hc_rtpc_port;
|
||||||
|
int hc_rtp_multicast:1;
|
||||||
|
long hc_rtsp_stream_id;
|
||||||
|
int hc_rtp_timeout;
|
||||||
|
|
||||||
struct http_client_ssl *hc_ssl; /* ssl internals */
|
struct http_client_ssl *hc_ssl; /* ssl internals */
|
||||||
|
|
||||||
|
@ -284,15 +292,45 @@ http_client_connect ( void *aux, http_ver_t ver,
|
||||||
void http_client_register ( http_client_t *hc );
|
void http_client_register ( http_client_t *hc );
|
||||||
void http_client_close ( http_client_t *hc );
|
void http_client_close ( http_client_t *hc );
|
||||||
|
|
||||||
int
|
int http_client_send( http_client_t *hc, http_cmd_t cmd,
|
||||||
http_client_send( http_client_t *hc, http_cmd_t cmd,
|
const char *path, const char *query,
|
||||||
const char *path, const char *query,
|
http_arg_list_t *header, void *body, size_t body_size );
|
||||||
http_arg_list_t *header, void *body, size_t body_size );
|
int http_client_simple( http_client_t *hc, const url_t *url);
|
||||||
int
|
int http_client_clear_state( http_client_t *hc );
|
||||||
http_client_simple( http_client_t *hc, const url_t *url);
|
int http_client_run( http_client_t *hc );
|
||||||
int
|
|
||||||
http_client_clear_state( http_client_t *hc );
|
/*
|
||||||
int
|
* RTSP helpers
|
||||||
http_client_run( http_client_t *hc );
|
*/
|
||||||
|
|
||||||
|
int rtsp_send( http_client_t *hc, http_cmd_t cmd, const char *path,
|
||||||
|
const char *query, http_arg_list_t *hdr );
|
||||||
|
|
||||||
|
void rtsp_clear_session( http_client_t *hc );
|
||||||
|
|
||||||
|
int rtsp_options_decode( http_client_t *hc );
|
||||||
|
static inline int rtsp_options( http_client_t *hc ) {
|
||||||
|
return rtsp_send(hc, RTSP_CMD_OPTIONS, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtsp_setup_decode( http_client_t *hc, int satip );
|
||||||
|
int rtsp_setup( http_client_t *hc, const char *path, const char *query,
|
||||||
|
const char *multicast_addr, int rtp_port, int rtpc_port );
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
rtsp_play( http_client_t *hc, const char *path, const char *query ) {
|
||||||
|
return rtsp_send(hc, RTSP_CMD_PLAY, path, query, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
rtsp_teardown( http_client_t *hc, const char *path, const char *query ) {
|
||||||
|
return rtsp_send(hc, RTSP_CMD_TEARDOWN, path, query, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rtsp_describe_decode( http_client_t *hc );
|
||||||
|
static inline int
|
||||||
|
rtsp_describe( http_client_t *hc, const char *path, const char *query ) {
|
||||||
|
return rtsp_send(hc, RTSP_CMD_DESCRIBE, path, query, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* HTTP_H_ */
|
#endif /* HTTP_H_ */
|
||||||
|
|
12
src/httpc.c
12
src/httpc.c
|
@ -581,7 +581,8 @@ http_client_finish( http_client_t *hc )
|
||||||
return http_client_flush(hc, res);
|
return http_client_flush(hc, res);
|
||||||
}
|
}
|
||||||
hc->hc_hsize = hc->hc_csize = 0;
|
hc->hc_hsize = hc->hc_csize = 0;
|
||||||
if (hc->hc_handle_location &&
|
if (hc->hc_version != RTSP_VERSION_1_0 &&
|
||||||
|
hc->hc_handle_location &&
|
||||||
(hc->hc_code == HTTP_STATUS_MOVED ||
|
(hc->hc_code == HTTP_STATUS_MOVED ||
|
||||||
hc->hc_code == HTTP_STATUS_FOUND ||
|
hc->hc_code == HTTP_STATUS_FOUND ||
|
||||||
hc->hc_code == HTTP_STATUS_SEE_OTHER ||
|
hc->hc_code == HTTP_STATUS_SEE_OTHER ||
|
||||||
|
@ -927,7 +928,12 @@ header:
|
||||||
goto next_header;
|
goto next_header;
|
||||||
}
|
}
|
||||||
hc->hc_rpos = 0;
|
hc->hc_rpos = 0;
|
||||||
hc->hc_in_data = 1;
|
if (hc->hc_version == RTSP_VERSION_1_0 && !hc->hc_csize) {
|
||||||
|
hc->hc_csize = -1;
|
||||||
|
hc->hc_in_data = 0;
|
||||||
|
} else {
|
||||||
|
hc->hc_in_data = 1;
|
||||||
|
}
|
||||||
res = http_client_data_received(hc, hc->hc_rbuf + hc->hc_hsize, len);
|
res = http_client_data_received(hc, hc->hc_rbuf + hc->hc_hsize, len);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return http_client_flush(hc, res);
|
return http_client_flush(hc, res);
|
||||||
|
@ -1168,6 +1174,7 @@ http_client_connect
|
||||||
hc = calloc(1, sizeof(http_client_t));
|
hc = calloc(1, sizeof(http_client_t));
|
||||||
hc->hc_aux = aux;
|
hc->hc_aux = aux;
|
||||||
hc->hc_io_size = 1024;
|
hc->hc_io_size = 1024;
|
||||||
|
hc->hc_rtsp_stream_id = -1;
|
||||||
|
|
||||||
TAILQ_INIT(&hc->hc_args);
|
TAILQ_INIT(&hc->hc_args);
|
||||||
TAILQ_INIT(&hc->hc_wqueue);
|
TAILQ_INIT(&hc->hc_wqueue);
|
||||||
|
@ -1216,6 +1223,7 @@ http_client_close ( http_client_t *hc )
|
||||||
while ((wcmd = TAILQ_FIRST(&hc->hc_wqueue)) != NULL)
|
while ((wcmd = TAILQ_FIRST(&hc->hc_wqueue)) != NULL)
|
||||||
http_client_cmd_destroy(hc, wcmd);
|
http_client_cmd_destroy(hc, wcmd);
|
||||||
http_client_ssl_free(hc);
|
http_client_ssl_free(hc);
|
||||||
|
rtsp_clear_session(hc);
|
||||||
free(hc->hc_location);
|
free(hc->hc_location);
|
||||||
free(hc->hc_rbuf);
|
free(hc->hc_rbuf);
|
||||||
free(hc->hc_data);
|
free(hc->hc_data);
|
||||||
|
|
|
@ -525,12 +525,13 @@ satip_frontend_store_pids(char *buf, uint16_t *pids, int count)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
satip_frontend_pid_changed( satip_rtsp_connection_t *rtsp,
|
satip_frontend_pid_changed( http_client_t *rtsp,
|
||||||
satip_frontend_t *lfe, const char *name )
|
satip_frontend_t *lfe, const char *name )
|
||||||
{
|
{
|
||||||
char *add, *del;
|
char *add, *del;
|
||||||
int i, j, r, count, any = lfe->sf_pids_any;
|
int i, j, r, count, any = lfe->sf_pids_any;
|
||||||
int deleted;
|
int deleted;
|
||||||
|
int max_pids_len = lfe->sf_device->sd_pids_len;
|
||||||
|
|
||||||
if (!lfe->sf_running)
|
if (!lfe->sf_running)
|
||||||
return;
|
return;
|
||||||
|
@ -552,7 +553,7 @@ satip_frontend_pid_changed( satip_rtsp_connection_t *rtsp,
|
||||||
lfe->sf_pids_tcount = lfe->sf_pids_count;
|
lfe->sf_pids_tcount = lfe->sf_pids_count;
|
||||||
pthread_mutex_unlock(&lfe->sf_dvr_lock);
|
pthread_mutex_unlock(&lfe->sf_dvr_lock);
|
||||||
|
|
||||||
r = satip_rtsp_play(rtsp, "all", NULL, NULL);
|
r = satip_rtsp_play(rtsp, "all", NULL, NULL, max_pids_len);
|
||||||
|
|
||||||
} else if (!lfe->sf_device->sd_pids_deladd ||
|
} else if (!lfe->sf_device->sd_pids_deladd ||
|
||||||
lfe->sf_pids_any_tuned ||
|
lfe->sf_pids_any_tuned ||
|
||||||
|
@ -572,7 +573,7 @@ satip_frontend_pid_changed( satip_rtsp_connection_t *rtsp,
|
||||||
lfe->sf_pids_tcount = lfe->sf_pids_count;
|
lfe->sf_pids_tcount = lfe->sf_pids_count;
|
||||||
pthread_mutex_unlock(&lfe->sf_dvr_lock);
|
pthread_mutex_unlock(&lfe->sf_dvr_lock);
|
||||||
|
|
||||||
r = satip_rtsp_play(rtsp, add, NULL, NULL);
|
r = satip_rtsp_play(rtsp, add, NULL, NULL, max_pids_len);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -638,7 +639,7 @@ satip_frontend_pid_changed( satip_rtsp_connection_t *rtsp,
|
||||||
pthread_mutex_unlock(&lfe->sf_dvr_lock);
|
pthread_mutex_unlock(&lfe->sf_dvr_lock);
|
||||||
|
|
||||||
if (add[0] != '\0' || del[0] != '\0')
|
if (add[0] != '\0' || del[0] != '\0')
|
||||||
r = satip_rtsp_play(rtsp, NULL, add, del);
|
r = satip_rtsp_play(rtsp, NULL, add, del, max_pids_len);
|
||||||
else
|
else
|
||||||
r = 0;
|
r = 0;
|
||||||
}
|
}
|
||||||
|
@ -651,9 +652,10 @@ static void *
|
||||||
satip_frontend_input_thread ( void *aux )
|
satip_frontend_input_thread ( void *aux )
|
||||||
{
|
{
|
||||||
#define PKTS 64
|
#define PKTS 64
|
||||||
|
#define HTTP_CMD_NONE 9874
|
||||||
satip_frontend_t *lfe = aux;
|
satip_frontend_t *lfe = aux;
|
||||||
mpegts_mux_instance_t *mmi = lfe->sf_mmi;
|
mpegts_mux_instance_t *mmi = lfe->sf_mmi;
|
||||||
satip_rtsp_connection_t *rtsp;
|
http_client_t *rtsp;
|
||||||
dvb_mux_t *lm;
|
dvb_mux_t *lm;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
uint8_t tsb[PKTS][1356 + 128];
|
uint8_t tsb[PKTS][1356 + 128];
|
||||||
|
@ -666,7 +668,6 @@ satip_frontend_input_thread ( void *aux )
|
||||||
size_t c;
|
size_t c;
|
||||||
int tc;
|
int tc;
|
||||||
tvhpoll_event_t ev[4];
|
tvhpoll_event_t ev[4];
|
||||||
tvhpoll_event_t evr;
|
|
||||||
tvhpoll_t *efd;
|
tvhpoll_t *efd;
|
||||||
int changing = 0, ms = -1, fatal = 0;
|
int changing = 0, ms = -1, fatal = 0;
|
||||||
uint32_t seq = -1, nseq;
|
uint32_t seq = -1, nseq;
|
||||||
|
@ -678,7 +679,8 @@ satip_frontend_input_thread ( void *aux )
|
||||||
|
|
||||||
lm = (dvb_mux_t *)mmi->mmi_mux;
|
lm = (dvb_mux_t *)mmi->mmi_mux;
|
||||||
|
|
||||||
rtsp = satip_rtsp_connection(lfe->sf_device);
|
rtsp = http_client_connect(lfe, RTSP_VERSION_1_0, "rstp",
|
||||||
|
lfe->sf_device->sd_info.addr, 554);
|
||||||
if (rtsp == NULL)
|
if (rtsp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -692,13 +694,13 @@ satip_frontend_input_thread ( void *aux )
|
||||||
ev[1].fd = lfe->sf_rtcp->fd;
|
ev[1].fd = lfe->sf_rtcp->fd;
|
||||||
ev[1].data.ptr = lfe->sf_rtcp;
|
ev[1].data.ptr = lfe->sf_rtcp;
|
||||||
ev[2].events = TVHPOLL_IN;
|
ev[2].events = TVHPOLL_IN;
|
||||||
ev[2].fd = rtsp->fd;
|
ev[2].fd = rtsp->hc_fd;
|
||||||
ev[2].data.ptr = rtsp;
|
ev[2].data.ptr = rtsp;
|
||||||
evr = ev[2];
|
|
||||||
ev[3].events = TVHPOLL_IN;
|
ev[3].events = TVHPOLL_IN;
|
||||||
ev[3].fd = lfe->sf_dvr_pipe.rd;
|
ev[3].fd = lfe->sf_dvr_pipe.rd;
|
||||||
ev[3].data.ptr = NULL;
|
ev[3].data.ptr = NULL;
|
||||||
tvhpoll_add(efd, ev, 4);
|
tvhpoll_add(efd, ev, 4);
|
||||||
|
rtsp->hc_efd = efd;
|
||||||
|
|
||||||
/* Read */
|
/* Read */
|
||||||
memset(&msg, 0, sizeof(msg));
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
@ -709,10 +711,10 @@ satip_frontend_input_thread ( void *aux )
|
||||||
iov[i].iov_len = sizeof(tsb[0]);
|
iov[i].iov_len = sizeof(tsb[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
r = satip_rtsp_setup(rtsp,
|
r = satip_rtsp_setup(rtsp,
|
||||||
lfe->sf_position, lfe->sf_number,
|
lfe->sf_position, lfe->sf_number,
|
||||||
lfe->sf_rtp_port, &lm->lm_tuning,
|
lfe->sf_rtp_port, &lm->lm_tuning);
|
||||||
1);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
tvherror("satip", "%s - failed to tune", buf);
|
tvherror("satip", "%s - failed to tune", buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -722,18 +724,6 @@ satip_frontend_input_thread ( void *aux )
|
||||||
|
|
||||||
while (tvheadend_running && !fatal) {
|
while (tvheadend_running && !fatal) {
|
||||||
|
|
||||||
if (rtsp->sending) {
|
|
||||||
if ((evr.events & TVHPOLL_OUT) == 0) {
|
|
||||||
evr.events |= TVHPOLL_OUT;
|
|
||||||
tvhpoll_add(efd, &evr, 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (evr.events & TVHPOLL_OUT) {
|
|
||||||
evr.events &= ~TVHPOLL_OUT;
|
|
||||||
tvhpoll_add(efd, &evr, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nfds = tvhpoll_wait(efd, ev, 1, ms);
|
nfds = tvhpoll_wait(efd, ev, 1, ms);
|
||||||
|
|
||||||
if (nfds > 0 && ev[0].data.ptr == NULL) {
|
if (nfds > 0 && ev[0].data.ptr == NULL) {
|
||||||
|
@ -747,7 +737,7 @@ satip_frontend_input_thread ( void *aux )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changing && rtsp->cmd == SATIP_RTSP_CMD_NONE) {
|
if (changing && rtsp->hc_cmd == HTTP_CMD_NONE) {
|
||||||
ms = -1;
|
ms = -1;
|
||||||
changing = 0;
|
changing = 0;
|
||||||
satip_frontend_pid_changed(rtsp, lfe, buf);
|
satip_frontend_pid_changed(rtsp, lfe, buf);
|
||||||
|
@ -757,31 +747,32 @@ satip_frontend_input_thread ( void *aux )
|
||||||
if (nfds < 1) continue;
|
if (nfds < 1) continue;
|
||||||
|
|
||||||
if (ev[0].data.ptr == rtsp) {
|
if (ev[0].data.ptr == rtsp) {
|
||||||
r = satip_rtsp_run(rtsp);
|
r = http_client_run(rtsp);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
tvhlog(LOG_ERR, "satip", "%s - RTSP error %d (%s) [%i-%i]",
|
tvhlog(LOG_ERR, "satip", "%s - RTSP error %d (%s) [%i-%i]",
|
||||||
buf, r, strerror(-r), rtsp->cmd, rtsp->code);
|
buf, r, strerror(-r), rtsp->hc_cmd, rtsp->hc_code);
|
||||||
fatal = 1;
|
fatal = 1;
|
||||||
} else if (r == SATIP_RTSP_READ_DONE) {
|
} else if (r == HTTP_CON_DONE) {
|
||||||
switch (rtsp->cmd) {
|
switch (rtsp->hc_cmd) {
|
||||||
case SATIP_RTSP_CMD_OPTIONS:
|
case RTSP_CMD_OPTIONS:
|
||||||
r = satip_rtsp_options_decode(rtsp);
|
r = rtsp_options_decode(rtsp);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
tvhlog(LOG_ERR, "satip", "%s - RTSP OPTIONS error %d (%s) [%i-%i]",
|
tvhlog(LOG_ERR, "satip", "%s - RTSP OPTIONS error %d (%s) [%i-%i]",
|
||||||
buf, r, strerror(-r), rtsp->cmd, rtsp->code);
|
buf, r, strerror(-r), rtsp->hc_cmd, rtsp->hc_code);
|
||||||
fatal = 1;
|
fatal = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SATIP_RTSP_CMD_SETUP:
|
case RTSP_CMD_SETUP:
|
||||||
r = satip_rtsp_setup_decode(rtsp);
|
r = rtsp_setup_decode(rtsp, 1);
|
||||||
if (r < 0 || rtsp->client_port != lfe->sf_rtp_port) {
|
if (r < 0 || rtsp->hc_rtp_port != lfe->sf_rtp_port ||
|
||||||
|
rtsp->hc_rtpc_port != lfe->sf_rtp_port + 1) {
|
||||||
tvhlog(LOG_ERR, "satip", "%s - RTSP SETUP error %d (%s) [%i-%i]",
|
tvhlog(LOG_ERR, "satip", "%s - RTSP SETUP error %d (%s) [%i-%i]",
|
||||||
buf, r, strerror(-r), rtsp->cmd, rtsp->code);
|
buf, r, strerror(-r), rtsp->hc_cmd, rtsp->hc_code);
|
||||||
fatal = 1;
|
fatal = 1;
|
||||||
} else {
|
} else {
|
||||||
tvhdebug("satip", "%s #%i - new session %s stream id %li",
|
tvhdebug("satip", "%s #%i - new session %s stream id %li",
|
||||||
lfe->sf_device->sd_info.addr, lfe->sf_number,
|
rtsp->hc_host, lfe->sf_number,
|
||||||
rtsp->session, rtsp->stream_id);
|
rtsp->hc_rtsp_session, rtsp->hc_rtsp_stream_id);
|
||||||
pthread_mutex_lock(&global_lock);
|
pthread_mutex_lock(&global_lock);
|
||||||
satip_frontend_default_tables(lfe, mmi->mmi_mux);
|
satip_frontend_default_tables(lfe, mmi->mmi_mux);
|
||||||
pthread_mutex_unlock(&global_lock);
|
pthread_mutex_unlock(&global_lock);
|
||||||
|
@ -789,21 +780,21 @@ satip_frontend_input_thread ( void *aux )
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (rtsp->code >= 400) {
|
if (rtsp->hc_code >= 400) {
|
||||||
tvhlog(LOG_ERR, "satip", "%s - RTSP cmd error %d (%s) [%i-%i]",
|
tvhlog(LOG_ERR, "satip", "%s - RTSP cmd error %d (%s) [%i-%i]",
|
||||||
buf, r, strerror(-r), rtsp->cmd, rtsp->code);
|
buf, r, strerror(-r), rtsp->hc_cmd, rtsp->hc_code);
|
||||||
fatal = 1;
|
fatal = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rtsp->cmd = SATIP_RTSP_CMD_NONE;
|
rtsp->hc_cmd = HTTP_CMD_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need to keep the session alive */
|
/* We need to keep the session alive */
|
||||||
if (rtsp->ping_time + rtsp->timeout / 2 < dispatch_clock &&
|
if (rtsp->hc_ping_time + rtsp->hc_rtp_timeout / 2 < dispatch_clock &&
|
||||||
rtsp->cmd == SATIP_RTSP_CMD_NONE)
|
rtsp->hc_cmd == HTTP_CMD_NONE)
|
||||||
satip_rtsp_options(rtsp);
|
rtsp_options(rtsp);
|
||||||
|
|
||||||
if (ev[0].data.ptr == lfe->sf_rtcp) {
|
if (ev[0].data.ptr == lfe->sf_rtcp) {
|
||||||
c = recv(lfe->sf_rtcp->fd, rtcp, sizeof(rtcp), MSG_DONTWAIT);
|
c = recv(lfe->sf_rtcp->fd, rtcp, sizeof(rtcp), MSG_DONTWAIT);
|
||||||
|
@ -875,29 +866,26 @@ satip_frontend_input_thread ( void *aux )
|
||||||
ev[2].data.ptr = NULL;
|
ev[2].data.ptr = NULL;
|
||||||
tvhpoll_rem(efd, ev, 3);
|
tvhpoll_rem(efd, ev, 3);
|
||||||
|
|
||||||
if (rtsp->stream_id) {
|
if (rtsp->hc_rtsp_stream_id >= 0) {
|
||||||
r = satip_rtsp_teardown(rtsp);
|
snprintf((char *)rtcp, sizeof(rtcp), "/stream=%li", rtsp->hc_rtsp_stream_id);
|
||||||
|
r = rtsp_teardown(rtsp, (char *)rtcp, NULL);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
tvhtrace("satip", "%s - bad teardown", buf);
|
tvhtrace("satip", "%s - bad teardown", buf);
|
||||||
} else {
|
} else {
|
||||||
if (r == SATIP_RTSP_INCOMPLETE) {
|
while (1) {
|
||||||
evr.events |= TVHPOLL_OUT;
|
r = http_client_run(rtsp);
|
||||||
tvhpoll_add(efd, &evr, 1);
|
if (r != HTTP_CON_RECEIVING && r != HTTP_CON_SENDING)
|
||||||
}
|
|
||||||
r = 0;
|
|
||||||
while (r == SATIP_RTSP_INCOMPLETE) {
|
|
||||||
if (!rtsp->sending) {
|
|
||||||
evr.events &= ~TVHPOLL_OUT;
|
|
||||||
tvhpoll_add(efd, &evr, 1);
|
|
||||||
}
|
|
||||||
nfds = tvhpoll_wait(efd, ev, 1, -1);
|
|
||||||
if (nfds < 0)
|
|
||||||
break;
|
break;
|
||||||
r = satip_rtsp_run(rtsp);
|
nfds = tvhpoll_wait(efd, ev, 1, -1);
|
||||||
|
if (nfds <= 0) {
|
||||||
|
if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
satip_rtsp_connection_close(rtsp);
|
http_client_close(rtsp);
|
||||||
|
|
||||||
tvhpoll_destroy(efd);
|
tvhpoll_destroy(efd);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "htsbuf.h"
|
#include "htsbuf.h"
|
||||||
#include "udp.h"
|
#include "udp.h"
|
||||||
|
#include "http.h"
|
||||||
#include "satip.h"
|
#include "satip.h"
|
||||||
|
|
||||||
#define SATIP_BUF_SIZE (4000*188)
|
#define SATIP_BUF_SIZE (4000*188)
|
||||||
|
@ -201,92 +202,14 @@ int satip_satconf_get_position
|
||||||
* RTSP part
|
* RTSP part
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
SATIP_RTSP_CMD_NONE,
|
|
||||||
SATIP_RTSP_CMD_OPTIONS,
|
|
||||||
SATIP_RTSP_CMD_SETUP,
|
|
||||||
SATIP_RTSP_CMD_PLAY,
|
|
||||||
SATIP_RTSP_CMD_TEARDOWN,
|
|
||||||
SATIP_RTSP_CMD_DESCRIBE
|
|
||||||
} satip_rtsp_cmd_t;
|
|
||||||
|
|
||||||
#define SATIP_RTSP_OK 1
|
|
||||||
#define SATIP_RTSP_READ_DONE 1
|
|
||||||
#define SATIP_RTSP_SEND_DONE 1
|
|
||||||
#define SATIP_RTSP_INCOMPLETE 0
|
|
||||||
|
|
||||||
typedef struct satip_rtsp_connection {
|
|
||||||
/* decoded answer */
|
|
||||||
int cseq;
|
|
||||||
int code;
|
|
||||||
char *header;
|
|
||||||
char *data;
|
|
||||||
/* state variables */
|
|
||||||
int sending;
|
|
||||||
satip_rtsp_cmd_t cmd;
|
|
||||||
int port;
|
|
||||||
int client_port;
|
|
||||||
int timeout;
|
|
||||||
char *session;
|
|
||||||
uint64_t stream_id;
|
|
||||||
/* internal data */
|
|
||||||
satip_device_t *device;
|
|
||||||
int fd;
|
|
||||||
char rbuf[4096];
|
|
||||||
size_t rsize;
|
|
||||||
size_t hsize; /* header size */
|
|
||||||
size_t csize; /* contents size (exclude header) */
|
|
||||||
char *wbuf;
|
|
||||||
size_t wpos;
|
|
||||||
size_t wsize;
|
|
||||||
htsbuf_queue_t wq2;
|
|
||||||
satip_rtsp_cmd_t wq2_cmd;
|
|
||||||
int wq2_loaded;
|
|
||||||
time_t ping_time;
|
|
||||||
} satip_rtsp_connection_t;
|
|
||||||
|
|
||||||
satip_rtsp_connection_t *
|
|
||||||
satip_rtsp_connection( satip_device_t *sd );
|
|
||||||
|
|
||||||
void
|
|
||||||
satip_rtsp_connection_close( satip_rtsp_connection_t *conn );
|
|
||||||
|
|
||||||
int
|
int
|
||||||
satip_rtsp_send_partial( satip_rtsp_connection_t *conn );
|
satip_rtsp_setup( http_client_t *hc,
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_send( satip_rtsp_connection_t *conn, htsbuf_queue_t *q,
|
|
||||||
satip_rtsp_cmd_t cmd );
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_run( satip_rtsp_connection_t *conn );
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_options_decode( satip_rtsp_connection_t *conn );
|
|
||||||
|
|
||||||
void
|
|
||||||
satip_rtsp_options( satip_rtsp_connection_t *conn );
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_setup_decode( satip_rtsp_connection_t *conn );
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_setup( satip_rtsp_connection_t *conn,
|
|
||||||
int src, int fe, int udp_port,
|
int src, int fe, int udp_port,
|
||||||
const dvb_mux_conf_t *dmc,
|
const dvb_mux_conf_t *dmc );
|
||||||
int connection_close );
|
|
||||||
|
|
||||||
int
|
int
|
||||||
satip_rtsp_play( satip_rtsp_connection_t *sd, const char *pids,
|
satip_rtsp_play( http_client_t *hc, const char *pids,
|
||||||
const char *addpids, const char *delpids );
|
const char *addpids, const char *delpids,
|
||||||
|
int max_pids_len );
|
||||||
int
|
|
||||||
satip_rtsp_teardown( satip_rtsp_connection_t *conn );
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_describe_decode( satip_rtsp_connection_t *conn );
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_describe( satip_rtsp_connection_t *conn );
|
|
||||||
|
|
||||||
#endif /* __TVH_SATIP_PRIVATE_H__ */
|
#endif /* __TVH_SATIP_PRIVATE_H__ */
|
||||||
|
|
|
@ -28,291 +28,6 @@
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
satip_rtsp_connection_t *
|
|
||||||
satip_rtsp_connection( satip_device_t *sd )
|
|
||||||
{
|
|
||||||
satip_rtsp_connection_t *conn;
|
|
||||||
char errbuf[256];
|
|
||||||
|
|
||||||
conn = calloc(1, sizeof(satip_rtsp_connection_t));
|
|
||||||
htsbuf_queue_init(&conn->wq2, 0);
|
|
||||||
conn->port = 554;
|
|
||||||
conn->timeout = 60;
|
|
||||||
conn->fd = tcp_connect(sd->sd_info.addr, conn->port,
|
|
||||||
errbuf, sizeof(errbuf), 2);
|
|
||||||
if (conn->fd < 0) {
|
|
||||||
tvhlog(LOG_ERR, "satip", "RTSP - unable to connect - %s", errbuf);
|
|
||||||
free(conn);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
conn->device = sd;
|
|
||||||
conn->ping_time = dispatch_clock;
|
|
||||||
return conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
satip_rtsp_connection_close( satip_rtsp_connection_t *conn )
|
|
||||||
{
|
|
||||||
|
|
||||||
htsbuf_queue_flush(&conn->wq2);
|
|
||||||
free(conn->session);
|
|
||||||
free(conn->header);
|
|
||||||
free(conn->data);
|
|
||||||
free(conn->wbuf);
|
|
||||||
if (conn->fd > 0)
|
|
||||||
close(conn->fd);
|
|
||||||
free(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_send_partial( satip_rtsp_connection_t *conn )
|
|
||||||
{
|
|
||||||
ssize_t r;
|
|
||||||
|
|
||||||
conn->sending = 1;
|
|
||||||
while (1) {
|
|
||||||
r = send(conn->fd, conn->wbuf + conn->wpos, conn->wsize - conn->wpos, MSG_DONTWAIT);
|
|
||||||
if (r < 0) {
|
|
||||||
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ||
|
|
||||||
errno == EINPROGRESS)
|
|
||||||
return SATIP_RTSP_INCOMPLETE;
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
conn->wpos += r;
|
|
||||||
if (conn->wpos >= conn->wsize) {
|
|
||||||
conn->sending = 0;
|
|
||||||
return SATIP_RTSP_SEND_DONE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return SATIP_RTSP_INCOMPLETE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_send( satip_rtsp_connection_t *conn, htsbuf_queue_t *q,
|
|
||||||
satip_rtsp_cmd_t cmd )
|
|
||||||
{
|
|
||||||
conn->ping_time = dispatch_clock;
|
|
||||||
conn->cmd = cmd;
|
|
||||||
free(conn->wbuf);
|
|
||||||
htsbuf_qprintf(q, "CSeq: %i\r\n\r\n", ++conn->cseq);
|
|
||||||
conn->wbuf = htsbuf_to_string(q);
|
|
||||||
conn->wsize = strlen(conn->wbuf);
|
|
||||||
conn->wpos = 0;
|
|
||||||
#if ENABLE_TRACE
|
|
||||||
tvhtrace("satip", "%s - sending RTSP cmd", conn->device->sd_info.addr);
|
|
||||||
tvhlog_hexdump("satip", conn->wbuf, conn->wsize);
|
|
||||||
#endif
|
|
||||||
return satip_rtsp_send_partial(conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
satip_rtsp_send2( satip_rtsp_connection_t *conn, htsbuf_queue_t *q,
|
|
||||||
satip_rtsp_cmd_t cmd )
|
|
||||||
{
|
|
||||||
conn->wq2_loaded = 1;
|
|
||||||
conn->wq2_cmd = cmd;
|
|
||||||
htsbuf_appendq(&conn->wq2, q);
|
|
||||||
return SATIP_RTSP_SEND_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
|
||||||
satip_rtsp_hstrip(char *h)
|
|
||||||
{
|
|
||||||
while (*h && *h <= ' ')
|
|
||||||
h++;
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_run( satip_rtsp_connection_t *conn )
|
|
||||||
{
|
|
||||||
char buf[1024], *saveptr, *argv[3], *d, *p, *p1;
|
|
||||||
htsbuf_queue_t header;
|
|
||||||
int cseq_seen;
|
|
||||||
ssize_t r;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if (conn->sending) {
|
|
||||||
r = satip_rtsp_send_partial(conn);
|
|
||||||
if (r < 0 || r == SATIP_RTSP_INCOMPLETE)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
r = recv(conn->fd, buf, sizeof(buf), MSG_DONTWAIT);
|
|
||||||
if (r == 0)
|
|
||||||
return -ESTRPIPE;
|
|
||||||
if (r < 0) {
|
|
||||||
if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
|
|
||||||
return SATIP_RTSP_INCOMPLETE;
|
|
||||||
return -errno;
|
|
||||||
}
|
|
||||||
#if ENABLE_TRACE
|
|
||||||
if (r > 0) {
|
|
||||||
tvhtrace("satip", "%s - received RTSP answer", conn->device->sd_info.addr);
|
|
||||||
tvhlog_hexdump("satip", buf, r);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (r + conn->rsize >= sizeof(conn->rbuf))
|
|
||||||
return -EINVAL;
|
|
||||||
memcpy(conn->rbuf + conn->rsize, buf, r);
|
|
||||||
conn->rsize += r;
|
|
||||||
conn->rbuf[conn->rsize] = '\0';
|
|
||||||
if (!conn->csize && conn->rsize > 3 &&
|
|
||||||
(d = strstr(conn->rbuf, "\r\n\r\n")) != NULL) {
|
|
||||||
conn->hsize = d - conn->rbuf + 4;
|
|
||||||
*d = '\0';
|
|
||||||
htsbuf_queue_init(&header, 0);
|
|
||||||
p = strtok_r(conn->rbuf, "\r\n", &saveptr);
|
|
||||||
if (p == NULL)
|
|
||||||
goto fail;
|
|
||||||
tvhtrace("satip", "%s - RTSP answer '%s'", conn->device->sd_info.addr, p);
|
|
||||||
if (http_tokenize(p, argv, 3, -1) != 3)
|
|
||||||
goto fail;
|
|
||||||
if (strcmp(argv[0], "RTSP/1.0"))
|
|
||||||
goto fail;
|
|
||||||
if ((conn->code = atoi(argv[1])) <= 0)
|
|
||||||
goto fail;
|
|
||||||
cseq_seen = 0;
|
|
||||||
while ((p = strtok_r(NULL, "\r\n", &saveptr)) != NULL) {
|
|
||||||
if (strncasecmp(p, "CSeq:", 5) == 0) {
|
|
||||||
p1 = satip_rtsp_hstrip(p + 5);
|
|
||||||
if (p1)
|
|
||||||
cseq_seen = conn->cseq == atoi(p1);
|
|
||||||
} else if (strncasecmp(p, "Content-Length:", 15) == 0) {
|
|
||||||
conn->csize = atoll(p + 15);
|
|
||||||
} else {
|
|
||||||
htsbuf_append(&header, p, strlen(p));
|
|
||||||
htsbuf_append(&header, "\n", 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!cseq_seen)
|
|
||||||
goto fail;
|
|
||||||
free(conn->header);
|
|
||||||
conn->header = htsbuf_to_string(&header);
|
|
||||||
htsbuf_queue_flush(&header);
|
|
||||||
free(conn->data);
|
|
||||||
conn->data = NULL;
|
|
||||||
if (!conn->csize)
|
|
||||||
goto processed;
|
|
||||||
if (conn->rsize > conn->hsize)
|
|
||||||
goto data;
|
|
||||||
} else if (conn->hsize + conn->csize >= conn->rsize) {
|
|
||||||
data:
|
|
||||||
conn->data = malloc(conn->csize + 1);
|
|
||||||
memcpy(conn->data, conn->rbuf + conn->hsize, conn->csize);
|
|
||||||
conn->data[conn->csize] = '\0';
|
|
||||||
processed:
|
|
||||||
len = conn->hsize + conn->csize;
|
|
||||||
memcpy(conn->rbuf, conn->rbuf + len, conn->rsize - len);
|
|
||||||
conn->rsize -= len;
|
|
||||||
#if ENABLE_TRACE
|
|
||||||
tvhtrace("satip", "%s - received RTSP header", conn->device->sd_info.addr);
|
|
||||||
tvhlog_hexdump("satip", conn->header, strlen(conn->header));
|
|
||||||
if (conn->csize) {
|
|
||||||
tvhtrace("satip", "%s - received RTSP data", conn->device->sd_info.addr);
|
|
||||||
tvhlog_hexdump("satip", conn->data, conn->csize);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
conn->hsize = conn->csize = 0;
|
|
||||||
/* second write */
|
|
||||||
if (conn->wq2_loaded && conn->code == 200 && !conn->rsize) {
|
|
||||||
r = satip_rtsp_send(conn, &conn->wq2, conn->wq2_cmd);
|
|
||||||
htsbuf_queue_flush(&conn->wq2);
|
|
||||||
conn->wq2_loaded = 0;
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
return SATIP_RTSP_READ_DONE;
|
|
||||||
fail:
|
|
||||||
htsbuf_queue_flush(&header);
|
|
||||||
conn->rsize = 0;
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
return SATIP_RTSP_INCOMPLETE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_options_decode( satip_rtsp_connection_t *conn )
|
|
||||||
{
|
|
||||||
char *argv[32], *s, *saveptr;
|
|
||||||
int i, n, what = 0;
|
|
||||||
|
|
||||||
s = strtok_r(conn->header, "\n", &saveptr);
|
|
||||||
while (s) {
|
|
||||||
n = http_tokenize(s, argv, 32, ',');
|
|
||||||
if (strcasecmp(argv[0], "Public:") == 0)
|
|
||||||
for (i = 1; i < n; i++) {
|
|
||||||
if (strcmp(argv[i], "DESCRIBE") == 0)
|
|
||||||
what |= 1;
|
|
||||||
else if (strcmp(argv[i], "SETUP") == 0)
|
|
||||||
what |= 2;
|
|
||||||
else if (strcmp(argv[i], "PLAY") == 0)
|
|
||||||
what |= 4;
|
|
||||||
else if (strcmp(argv[i], "TEARDOWN") == 0)
|
|
||||||
what |= 8;
|
|
||||||
}
|
|
||||||
s = strtok_r(NULL, "\n", &saveptr);
|
|
||||||
}
|
|
||||||
return (conn->code != 200 && what != 0x0f) ? -EIO : SATIP_RTSP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
satip_rtsp_options( satip_rtsp_connection_t *conn )
|
|
||||||
{
|
|
||||||
htsbuf_queue_t q;
|
|
||||||
htsbuf_queue_init(&q, 0);
|
|
||||||
htsbuf_qprintf(&q,
|
|
||||||
"OPTIONS rtsp://%s/ RTSP/1.0\r\n",
|
|
||||||
conn->device->sd_info.addr);
|
|
||||||
satip_rtsp_send(conn, &q, SATIP_RTSP_CMD_OPTIONS);
|
|
||||||
htsbuf_queue_flush(&q);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_setup_decode( satip_rtsp_connection_t *conn )
|
|
||||||
{
|
|
||||||
char *argv[32], *s, *saveptr;
|
|
||||||
int i, n;
|
|
||||||
|
|
||||||
if (conn->code != 200)
|
|
||||||
return -EIO;
|
|
||||||
conn->client_port = 0;
|
|
||||||
s = strtok_r(conn->header, "\n", &saveptr);
|
|
||||||
while (s) {
|
|
||||||
n = http_tokenize(s, argv, 32, ';');
|
|
||||||
if (strcasecmp(argv[0], "Session:") == 0) {
|
|
||||||
conn->session = strdup(argv[1]);
|
|
||||||
for (i = 2; i < n; i++) {
|
|
||||||
if (strncasecmp(argv[i], "timeout=", 8) == 0) {
|
|
||||||
conn->timeout = atoi(argv[i] + 8);
|
|
||||||
if (conn->timeout <= 20 || conn->timeout > 3600)
|
|
||||||
return -EIO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (strcasecmp(argv[0], "com.ses.streamID:") == 0) {
|
|
||||||
conn->stream_id = atoll(argv[1]);
|
|
||||||
/* zero is valid stream id per specification */
|
|
||||||
if (argv[1][0] == '0' && argv[1][0] == '\0')
|
|
||||||
conn->stream_id = 0;
|
|
||||||
else if (conn->stream_id <= 0)
|
|
||||||
return -EIO;
|
|
||||||
} else if (strcasecmp(argv[0], "Transport:") == 0) {
|
|
||||||
if (strcasecmp(argv[1], "RTP/AVP"))
|
|
||||||
return -EIO;
|
|
||||||
if (strcasecmp(argv[2], "unicast"))
|
|
||||||
return -EIO;
|
|
||||||
for (i = 2; i < n; i++) {
|
|
||||||
if (strncmp(argv[i], "client_port=", 12) == 0)
|
|
||||||
conn->client_port = atoi(argv[i] + 12);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s = strtok_r(NULL, "\n", &saveptr);
|
|
||||||
}
|
|
||||||
return SATIP_RTSP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct tvh2satip {
|
typedef struct tvh2satip {
|
||||||
int t; ///< TVH internal value
|
int t; ///< TVH internal value
|
||||||
|
@ -354,9 +69,8 @@ satip_rtsp_add_val(const char *name, char *buf, uint32_t val)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
satip_rtsp_setup( satip_rtsp_connection_t *conn, int src, int fe,
|
satip_rtsp_setup( http_client_t *hc, int src, int fe,
|
||||||
int udp_port, const dvb_mux_conf_t *dmc,
|
int udp_port, const dvb_mux_conf_t *dmc )
|
||||||
int connection_close )
|
|
||||||
{
|
{
|
||||||
static tvh2satip_t msys[] = {
|
static tvh2satip_t msys[] = {
|
||||||
{ .t = DVB_SYS_DVBT, "dvbt" },
|
{ .t = DVB_SYS_DVBT, "dvbt" },
|
||||||
|
@ -432,10 +146,9 @@ satip_rtsp_setup( satip_rtsp_connection_t *conn, int src, int fe,
|
||||||
};
|
};
|
||||||
|
|
||||||
char buf[512];
|
char buf[512];
|
||||||
htsbuf_queue_t q;
|
char *stream = NULL;
|
||||||
int r;
|
char _stream[32];
|
||||||
|
|
||||||
htsbuf_queue_init(&q, 0);
|
|
||||||
if (src > 0)
|
if (src > 0)
|
||||||
sprintf(buf, "src=%i&", src);
|
sprintf(buf, "src=%i&", src);
|
||||||
else
|
else
|
||||||
|
@ -469,27 +182,15 @@ satip_rtsp_setup( satip_rtsp_connection_t *conn, int src, int fe,
|
||||||
ADD(u.dmc_fe_ofdm.guard_interval, gi, "18");
|
ADD(u.dmc_fe_ofdm.guard_interval, gi, "18");
|
||||||
}
|
}
|
||||||
tvhtrace("satip", "setup params - %s", buf);
|
tvhtrace("satip", "setup params - %s", buf);
|
||||||
if (conn->stream_id > 0)
|
if (hc->hc_rtsp_stream_id >= 0)
|
||||||
htsbuf_qprintf(&q, "SETUP rtsp://%s/stream=%li?",
|
snprintf(stream = _stream, sizeof(_stream), "/stream=%li",
|
||||||
conn->device->sd_info.addr, conn->stream_id);
|
hc->hc_rtsp_stream_id);
|
||||||
else
|
return rtsp_setup(hc, stream, buf, NULL, udp_port, udp_port + 1);
|
||||||
htsbuf_qprintf(&q, "SETUP rtsp://%s/?", conn->device->sd_info.addr);
|
|
||||||
htsbuf_qprintf(&q,
|
|
||||||
"%s RTSP/1.0\r\nTransport: RTP/AVP;unicast;client_port=%i-%i\r\n",
|
|
||||||
buf, udp_port, udp_port+1);
|
|
||||||
if (conn->session)
|
|
||||||
htsbuf_qprintf(&q, "Session: %s\r\n", conn->session);
|
|
||||||
if (connection_close)
|
|
||||||
htsbuf_qprintf(&q, "Connection: close\r\n");
|
|
||||||
r = satip_rtsp_send(conn, &q, SATIP_RTSP_CMD_SETUP);
|
|
||||||
htsbuf_queue_flush(&q);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
satip_rtsp_pids_strip( satip_rtsp_connection_t *conn, const char *s )
|
satip_rtsp_pids_strip( const char *s, int maxlen )
|
||||||
{
|
{
|
||||||
int maxlen = conn->device->sd_pids_len;
|
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
|
@ -508,15 +209,19 @@ satip_rtsp_pids_strip( satip_rtsp_connection_t *conn, const char *s )
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
satip_rtsp_play( satip_rtsp_connection_t *conn, const char *pids,
|
satip_rtsp_play( http_client_t *hc, const char *pids,
|
||||||
const char *addpids, const char *delpids )
|
const char *addpids, const char *delpids,
|
||||||
|
int max_pids_len )
|
||||||
{
|
{
|
||||||
htsbuf_queue_t q;
|
htsbuf_queue_t q;
|
||||||
|
char *stream = NULL;
|
||||||
|
char _stream[32];
|
||||||
|
char *query;
|
||||||
int r, split = 0;
|
int r, split = 0;
|
||||||
|
|
||||||
pids = satip_rtsp_pids_strip(conn, pids);
|
pids = satip_rtsp_pids_strip(pids , max_pids_len);
|
||||||
addpids = satip_rtsp_pids_strip(conn, addpids);
|
addpids = satip_rtsp_pids_strip(addpids, max_pids_len);
|
||||||
delpids = satip_rtsp_pids_strip(conn, delpids);
|
delpids = satip_rtsp_pids_strip(delpids, max_pids_len);
|
||||||
|
|
||||||
if (pids == NULL && addpids == NULL && delpids == NULL)
|
if (pids == NULL && addpids == NULL && delpids == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -524,8 +229,6 @@ satip_rtsp_play( satip_rtsp_connection_t *conn, const char *pids,
|
||||||
//printf("pids = '%s' addpids = '%s' delpids = '%s'\n", pids, addpids, delpids);
|
//printf("pids = '%s' addpids = '%s' delpids = '%s'\n", pids, addpids, delpids);
|
||||||
|
|
||||||
htsbuf_queue_init(&q, 0);
|
htsbuf_queue_init(&q, 0);
|
||||||
htsbuf_qprintf(&q, "PLAY rtsp://%s/stream=%li?",
|
|
||||||
conn->device->sd_info.addr, conn->stream_id);
|
|
||||||
/* pids setup and add/del requests cannot be mixed per specification */
|
/* pids setup and add/del requests cannot be mixed per specification */
|
||||||
if (pids) {
|
if (pids) {
|
||||||
htsbuf_qprintf(&q, "pids=%s", pids);
|
htsbuf_qprintf(&q, "pids=%s", pids);
|
||||||
|
@ -535,7 +238,7 @@ satip_rtsp_play( satip_rtsp_connection_t *conn, const char *pids,
|
||||||
if (addpids) {
|
if (addpids) {
|
||||||
if (delpids) {
|
if (delpids) {
|
||||||
/* try to maintain the maximum request size - simple split */
|
/* try to maintain the maximum request size - simple split */
|
||||||
if (strlen(addpids) + strlen(delpids) <= conn->device->sd_pids_len)
|
if (strlen(addpids) + strlen(delpids) <= max_pids_len)
|
||||||
split = 1;
|
split = 1;
|
||||||
else
|
else
|
||||||
htsbuf_append(&q, "&", 1);
|
htsbuf_append(&q, "&", 1);
|
||||||
|
@ -544,55 +247,11 @@ satip_rtsp_play( satip_rtsp_connection_t *conn, const char *pids,
|
||||||
htsbuf_qprintf(&q, "addpids=%s", addpids);
|
htsbuf_qprintf(&q, "addpids=%s", addpids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
htsbuf_qprintf(&q, " RTSP/1.0\r\nSession: %s\r\n", conn->session);
|
if (hc->hc_rtsp_stream_id >= 0)
|
||||||
r = satip_rtsp_send(conn, &q, SATIP_RTSP_CMD_PLAY);
|
snprintf(stream = _stream, sizeof(_stream), "/stream=%li",
|
||||||
htsbuf_queue_flush(&q);
|
hc->hc_rtsp_stream_id);
|
||||||
if (r < 0 || !split)
|
query = htsbuf_to_string(&q);
|
||||||
return r;
|
r = rtsp_play(hc, stream, query);
|
||||||
|
free(query);
|
||||||
htsbuf_queue_init(&q, 0);
|
|
||||||
htsbuf_qprintf(&q, "PLAY rtsp://%s/stream=%li?",
|
|
||||||
conn->device->sd_info.addr, conn->stream_id);
|
|
||||||
htsbuf_qprintf(&q, "addpids=%s", addpids);
|
|
||||||
htsbuf_qprintf(&q, " RTSP/1.0\r\nSession: %s\r\n", conn->session);
|
|
||||||
r = satip_rtsp_send2(conn, &q, SATIP_RTSP_CMD_PLAY);
|
|
||||||
htsbuf_queue_flush(&q);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_teardown( satip_rtsp_connection_t *conn )
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
htsbuf_queue_t q;
|
|
||||||
htsbuf_queue_init(&q, 0);
|
|
||||||
htsbuf_qprintf(&q,
|
|
||||||
"TEARDOWN rtsp://%s/stream=%li RTSP/1.0\r\nSession: %s\r\n",
|
|
||||||
conn->device->sd_info.addr, conn->stream_id, conn->session);
|
|
||||||
r = satip_rtsp_send(conn, &q, SATIP_RTSP_CMD_TEARDOWN);
|
|
||||||
htsbuf_queue_flush(&q);
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_describe_decode( satip_rtsp_connection_t *conn )
|
|
||||||
{
|
|
||||||
printf("describe: %i\n", conn->code);
|
|
||||||
printf("header:\n%s\n", conn->header);
|
|
||||||
printf("data:\n%s\n", conn->data);
|
|
||||||
return SATIP_RTSP_SEND_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
satip_rtsp_describe( satip_rtsp_connection_t *conn )
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
|
|
||||||
htsbuf_queue_t q;
|
|
||||||
htsbuf_queue_init(&q, 0);
|
|
||||||
htsbuf_qprintf(&q,
|
|
||||||
"DESCRIBE rtsp://%s/ RTSP/1.0\r\n", conn->device->sd_info.addr);
|
|
||||||
r = satip_rtsp_send(conn, &q, SATIP_RTSP_CMD_DESCRIBE);
|
|
||||||
htsbuf_queue_flush(&q);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
199
src/rtsp.c
Normal file
199
src/rtsp.c
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
* Tvheadend - RTSP routines
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Jaroslav Kysela
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include "tvheadend.h"
|
||||||
|
#include "htsbuf.h"
|
||||||
|
#include "tcp.h"
|
||||||
|
#include "http.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utils
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
rtsp_send( http_client_t *hc, http_cmd_t cmd,
|
||||||
|
const char *path, const char *query,
|
||||||
|
http_arg_list_t *hdr )
|
||||||
|
{
|
||||||
|
http_arg_list_t h;
|
||||||
|
size_t blen = 7 + strlen(hc->hc_host) + (path ? strlen(path) : 1) + 1;
|
||||||
|
char *buf = alloca(blen);
|
||||||
|
|
||||||
|
if (hc->hc_rtsp_session && cmd != RTSP_CMD_OPTIONS) {
|
||||||
|
if (hdr == NULL) {
|
||||||
|
hdr = &h;
|
||||||
|
http_arg_init(&h);
|
||||||
|
}
|
||||||
|
http_arg_set(hdr, "Session", hc->hc_rtsp_session);
|
||||||
|
}
|
||||||
|
snprintf(buf, blen, "rtsp://%s%s", hc->hc_host, path ? path : "/");
|
||||||
|
return http_client_send(hc, cmd, buf, query, hdr, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rtsp_clear_session( http_client_t *hc )
|
||||||
|
{
|
||||||
|
free(hc->hc_rtsp_session);
|
||||||
|
free(hc->hc_rtp_dest);
|
||||||
|
hc->hc_rtp_port = 0;
|
||||||
|
hc->hc_rtpc_port = 0;
|
||||||
|
hc->hc_rtsp_session = NULL;
|
||||||
|
hc->hc_rtp_dest = NULL;
|
||||||
|
hc->hc_rtp_multicast = 0;
|
||||||
|
hc->hc_rtsp_stream_id = -1;
|
||||||
|
hc->hc_rtp_timeout = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Options
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
rtsp_options_decode( http_client_t *hc )
|
||||||
|
{
|
||||||
|
char *argv[32], *p;
|
||||||
|
int i, n, what = 0;
|
||||||
|
|
||||||
|
p = http_arg_get(&hc->hc_args, "Public");
|
||||||
|
n = http_tokenize(p, argv, 32, ',');
|
||||||
|
for (i = 1; i < n; i++) {
|
||||||
|
if (strcmp(argv[i], "DESCRIBE") == 0)
|
||||||
|
what |= 1;
|
||||||
|
else if (strcmp(argv[i], "SETUP") == 0)
|
||||||
|
what |= 2;
|
||||||
|
else if (strcmp(argv[i], "PLAY") == 0)
|
||||||
|
what |= 4;
|
||||||
|
else if (strcmp(argv[i], "TEARDOWN") == 0)
|
||||||
|
what |= 8;
|
||||||
|
}
|
||||||
|
return (hc->hc_code != 200 && what != 0x0f) ? -EIO : HTTP_CON_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rtsp_setup_decode( http_client_t *hc, int satip )
|
||||||
|
{
|
||||||
|
char *argv[32], *argv2[2], *p;
|
||||||
|
int i, n, j;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{ http_arg_t *ra;
|
||||||
|
TAILQ_FOREACH(ra, &hc->hc_args, link)
|
||||||
|
printf(" %s: %s\n", ra->key, ra->val); }
|
||||||
|
#endif
|
||||||
|
rtsp_clear_session(hc);
|
||||||
|
if (hc->hc_code != 200)
|
||||||
|
return -EIO;
|
||||||
|
p = http_arg_get(&hc->hc_args, "Session");
|
||||||
|
if (p == NULL)
|
||||||
|
return -EIO;
|
||||||
|
n = http_tokenize(p, argv, 32, ';');
|
||||||
|
if (n < 1)
|
||||||
|
return -EIO;
|
||||||
|
hc->hc_rtsp_session = strdup(argv[0]);
|
||||||
|
for (i = 1; i < n; i++) {
|
||||||
|
if (strncasecmp(argv[i], "timeout=", 8) == 0) {
|
||||||
|
hc->hc_rtp_timeout = atoi(argv[i] + 8);
|
||||||
|
if (hc->hc_rtp_timeout <= 20 || hc->hc_rtp_timeout > 3600)
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (satip) {
|
||||||
|
p = http_arg_get(&hc->hc_args, "com.ses.streamID");
|
||||||
|
if (p == NULL)
|
||||||
|
return -EIO;
|
||||||
|
/* zero is valid stream id per specification */
|
||||||
|
while (*p && (*p == '0' || *p < ' '))
|
||||||
|
p++;
|
||||||
|
if (p[0] == '0' && p[1] == '\0') {
|
||||||
|
hc->hc_rtsp_stream_id = 0;
|
||||||
|
} else {
|
||||||
|
hc->hc_rtsp_stream_id = atoll(p);
|
||||||
|
if (hc->hc_rtsp_stream_id <= 0)
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p = http_arg_get(&hc->hc_args, "Transport");
|
||||||
|
if (p == NULL)
|
||||||
|
return -EIO;
|
||||||
|
n = http_tokenize(p, argv, 32, ';');
|
||||||
|
if (n < 3)
|
||||||
|
return -EIO;
|
||||||
|
if (strcasecmp(argv[0], "RTP/AVP"))
|
||||||
|
return -EIO;
|
||||||
|
hc->hc_rtp_multicast = strcasecmp(argv[1], "multicast") == 0;
|
||||||
|
if (strcasecmp(argv[1], "unicast") && !hc->hc_rtp_multicast)
|
||||||
|
return -EIO;
|
||||||
|
for (i = 2; i < n; i++) {
|
||||||
|
if (strncmp(argv[i], "destination=", 12) == 0)
|
||||||
|
hc->hc_rtp_dest = strdup(argv[i] + 12);
|
||||||
|
else if (strncmp(argv[i], "client_port=", 12) == 0) {
|
||||||
|
j = http_tokenize(argv[i] + 12, argv2, 2, '-');
|
||||||
|
if (j > 0) {
|
||||||
|
hc->hc_rtp_port = atoi(argv2[0]);
|
||||||
|
if (hc->hc_rtp_port <= 0)
|
||||||
|
return -EIO;
|
||||||
|
if (j > 1) {
|
||||||
|
hc->hc_rtpc_port = atoi(argv2[1]);
|
||||||
|
if (hc->hc_rtpc_port <= 0)
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return HTTP_CON_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rtsp_setup( http_client_t *hc,
|
||||||
|
const char *path, const char *query,
|
||||||
|
const char *multicast_addr,
|
||||||
|
int rtp_port, int rtpc_port )
|
||||||
|
{
|
||||||
|
http_arg_list_t h;
|
||||||
|
char transport[256];
|
||||||
|
|
||||||
|
if (multicast_addr) {
|
||||||
|
snprintf(transport, sizeof(transport),
|
||||||
|
"RTP/AVP;multicast;destination=%s;ttl=1;client_port=%i-%i",
|
||||||
|
multicast_addr, rtp_port, rtpc_port);
|
||||||
|
} else {
|
||||||
|
snprintf(transport, sizeof(transport),
|
||||||
|
"RTP/AVP;unicast;client_port=%i-%i", rtp_port, rtpc_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
http_arg_init(&h);
|
||||||
|
http_arg_set(&h, "Transport", transport);
|
||||||
|
return rtsp_send(hc, RTSP_CMD_SETUP, path, query, &h);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rtsp_describe_decode( http_client_t *hc )
|
||||||
|
{
|
||||||
|
http_arg_t *ra;
|
||||||
|
|
||||||
|
/* TODO: Probably rewrite the data to the htsmsg tree ? */
|
||||||
|
printf("describe: %i\n", hc->hc_code);
|
||||||
|
TAILQ_FOREACH(ra, &hc->hc_args, link)
|
||||||
|
printf(" %s: %s\n", ra->key, ra->val);
|
||||||
|
printf("data:\n%s\n", hc->hc_data);
|
||||||
|
return HTTP_CON_OK;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue