/* * Setup RTSP(S) connection */ static int iptv_rtsp_start ( iptv_mux_t *im, const char *raw, const url_t *u ) { rtsp_priv_t *rp; http_client_t *hc; udp_connection_t *rtp, *rtcp; int r; if (!(hc = http_client_connect(im, RTSP_VERSION_1_0, u->scheme, u->host, u->port, NULL))) return SM_CODE_TUNING_FAILED; if (u->user) hc->hc_rtsp_user = strdup(u->user); if (u->pass) hc->hc_rtsp_pass = strdup(u->pass); if (udp_bind_double(&rtp, &rtcp, "IPTV", "rtp", "rtcp", NULL, 0, NULL, 128*1024, 16384, 4*1024, 4*1024) < 0) { http_client_close(hc); return SM_CODE_TUNING_FAILED; } hc->hc_hdr_received = iptv_rtsp_header; hc->hc_data_received = iptv_rtsp_data; hc->hc_handle_location = 1; /* allow redirects */ hc->hc_rtsp_keep_alive_cmd = RTSP_CMD_GET_PARAMETER; /* start keep alive loop with GET_PARAMETER */ http_client_register(hc); /* register to the HTTP thread */ r = rtsp_setup(hc, u->path, u->query, NULL, ntohs(IP_PORT(rtp->ip)), ntohs(IP_PORT(rtcp->ip))); if (r < 0) { udp_close(rtcp); udp_close(rtp); http_client_close(hc); return SM_CODE_TUNING_FAILED; } rp = calloc(1, sizeof(*rp)); rp->rtcp_info = calloc(1, sizeof(iptv_rtcp_info_t)); rtcp_init(rp->rtcp_info); rp->rtcp_info->connection = rtcp; rp->hc = hc; udp_multirecv_init(&rp->um, IPTV_PKTS, IPTV_PKT_PAYLOAD); rp->path = strdup(u->path ?: ""); rp->query = strdup(u->query ?: ""); im->im_data = rp; im->mm_iptv_fd = rtp->fd; im->mm_iptv_connection = rtp; im->mm_iptv_fd2 = rtcp->fd; im->mm_iptv_connection2 = rtcp; return 0; }
static void download_fetch(void *aux) { download_t *dn = aux; http_client_t *hc; url_t u; urlinit(&u); if (dn->url == NULL) goto done; if (strncmp(dn->url, "file://", 7) == 0) { download_file(dn, dn->url + 7); goto done; } if (strncmp(dn->url, "pipe://", 7) == 0) { download_pipe(dn, dn->url + 7); goto done; } if (dn->http_client) { http_client_close(dn->http_client); dn->http_client = NULL; } if (urlparse(dn->url, &u) < 0) { tvherror(dn->log, "wrong url"); goto stop; } hc = http_client_connect(dn, HTTP_VERSION_1_1, u.scheme, u.host, u.port, NULL); if (hc == NULL) { tvherror(dn->log, "unable to open http client"); goto stop; } hc->hc_handle_location = 1; hc->hc_data_limit = 1024*1024; hc->hc_data_complete = download_fetch_complete; http_client_register(hc); http_client_ssl_peer_verify(hc, dn->ssl_peer_verify); if (http_client_simple(hc, &u) < 0) { http_client_close(hc); tvherror(dn->log, "unable to send http command"); goto stop; } dn->http_client = hc; goto done; stop: if (dn->stop) dn->stop(dn->aux); done: urlreset(&u); }
/* * Stop connection */ static void iptv_rtsp_stop ( iptv_mux_t *im ) { rtsp_priv_t *rp = im->im_data; int play; lock_assert(&global_lock); if (rp == NULL) return; play = rp->play; im->im_data = NULL; rp->hc->hc_aux = NULL; if (play) rtsp_teardown(rp->hc, rp->path, ""); pthread_mutex_unlock(&iptv_lock); gtimer_disarm(&rp->alive_timer); udp_multirecv_free(&rp->um); if (!play) http_client_close(rp->hc); free(rp->path); free(rp->query); rtcp_destroy(rp->rtcp_info); free(rp->rtcp_info); free(rp); pthread_mutex_lock(&iptv_lock); }
/* * Setup HTTP(S) connection */ static int iptv_http_start ( iptv_mux_t *im, const char *raw, const url_t *u ) { http_client_t *hc; int r; if (!(hc = http_client_connect(im, HTTP_VERSION_1_1, u->scheme, u->host, u->port, NULL))) return SM_CODE_TUNING_FAILED; hc->hc_hdr_create = iptv_http_create_header; hc->hc_hdr_received = iptv_http_header; hc->hc_data_received = iptv_http_data; hc->hc_data_complete = iptv_http_complete; hc->hc_handle_location = 1; /* allow redirects */ hc->hc_io_size = 128*1024; /* increase buffering */ http_client_register(hc); /* register to the HTTP thread */ r = http_client_simple(hc, u); if (r < 0) { http_client_close(hc); return SM_CODE_TUNING_FAILED; } im->im_data = hc; sbuf_init_fixed(&im->mm_iptv_buffer, IPTV_BUF_SIZE); return 0; }
/* * Cleanup for http_xml_send() */ static void http_xml_send_cleanup(void *arg) { struct http_client_connection *cc = arg; http_client_close(&cc); }
static void download_fetch_done(void *aux) { http_client_t *hc = aux; download_t *dm = hc->hc_aux; if (dm->http_client) { dm->http_client = NULL; http_client_close((http_client_t *)aux); } }
/* * Stop connection */ static void iptv_http_stop ( iptv_mux_t *im ) { http_client_t *hc = im->im_data; hc->hc_aux = NULL; pthread_mutex_unlock(&iptv_lock); http_client_close(hc); pthread_mutex_lock(&iptv_lock); }
void download_done( download_t *dn ) { if (dn->http_client) { http_client_close(dn->http_client); dn->http_client = NULL; } gtimer_disarm(&dn->fetch_timer); free(dn->log); dn->log = NULL; free(dn->url); dn->url = NULL; }
void download_start( download_t *dn, const char *url, void *aux ) { if (dn->http_client) { http_client_close(dn->http_client); dn->http_client = NULL; } if (url) dn->url = strdup(url); dn->aux = aux; gtimer_arm(&dn->fetch_timer, download_fetch, dn, 0); }
static void satip_discovery_destroy(satip_discovery_t *d, int unlink) { if (d == NULL) return; if (unlink) { satip_discoveries_count--; TAILQ_REMOVE(&satip_discoveries, d, disc_link); } if (d->http_client) http_client_close(d->http_client); urlreset(&d->url); free(d->myaddr); free(d->location); free(d->server); free(d->uuid); free(d->bootid); free(d->configid); free(d->deviceid); free(d); }
static void iptv_rtsp_close_cb ( void *aux ) { http_client_close((http_client_t *)aux); }
/*M \emph{Simple HTTP streaming server main loop.} The mainloop opens the MPEG Audio file \verb|filename|, reads each frame into an rtp packet and sends it out using HTTP. After sending a packet, the mainloop sleeps for the duration of the packet, synchronizing itself when the sleep is not accurate enough. If the sleep desynchronizes itself from the stream more than \verb|MAX_WAIT_TIME|, the synchronization is reset. **/ int poc_mainloop(http_server_t *server, char *filename, int quiet) { /*M Open file for reading. **/ file_t mp3_file; if (!file_open_read(&mp3_file, filename)) { fprintf(stderr, "Could not open mp3 file: %s\n", filename); return 0; } if (!quiet) fprintf(stderr, "\rStreaming %s...\n", filename); static long wait_time = 0; unsigned long frame_time = 0; mp3_frame_t frame; /*M Cycle through the frames and send them using HTTP. **/ while ((mp3_next_frame(&mp3_file, &frame) >= 0) && !finished) { /*M Get start time for this frame iteration. **/ struct timeval tv; gettimeofday(&tv, NULL); unsigned long start_sec, start_usec; start_sec = tv.tv_sec; start_usec = tv.tv_usec; /*M Go through HTTP main routine and check for timeouts, received data, etc... **/ if (!http_server_main(server, NULL)) { fprintf(stderr, "Http main error\n"); return 0; } /*M Write frame to HTTP clients. **/ int i; for (i = 0; i < server->num_clients; i++) { if ((server->clients[i].fd != -1) && (server->clients[i].found >= 2)) { int ret; ret = unix_write(server->clients[i].fd, frame.raw, frame.frame_size); if (ret != frame.frame_size) { fprintf(stderr, "Error writing to client %d: %d\n", i, ret); http_client_close(server, server->clients + i); } } } frame_time += frame.usec; wait_time += frame.usec; /*M Sleep for duration of frame. **/ if (wait_time > 1000) usleep(wait_time); /*M Print information. **/ if (!quiet) { static int count = 0; if ((count++) % 10 == 0) { if (mp3_file.size > 0) { fprintf(stderr, "\r%02ld:%02ld/%02ld:%02ld %7ld/%7ld (%3ld%%) %3ldkbit/s %4ldb ", (frame_time/1000000) / 60, (frame_time/1000000) % 60, (long)((float)(frame_time/1000) / ((float)mp3_file.offset+1) * (float)mp3_file.size) / 60000, (long)((float)(frame_time/1000) / ((float)mp3_file.offset+1) * (float)mp3_file.size) / 1000 % 60, mp3_file.offset, mp3_file.size, (long)(100*(float)mp3_file.offset/(float)mp3_file.size), frame.bitrate, frame.frame_size); } else { fprintf(stderr, "\r%02ld:%02ld %ld %3ldkbit/s %4ldb ", (frame_time/1000000) / 60, (frame_time/1000000) % 60, mp3_file.offset, frame.bitrate, frame.frame_size); } } fflush(stderr); } /*M Get length of iteration. **/ gettimeofday(&tv, NULL); unsigned long len = (tv.tv_sec - start_sec) * 1000000 + (tv.tv_usec - start_usec); wait_time -= len; if (abs(wait_time) > MAX_WAIT_TIME) wait_time = 0; } if (!file_close(&mp3_file)) { fprintf(stderr, "Could not close mp3 file %s\n", filename); return 0; } return 1; }