/* * cmyth_livetv_chain_setup(cmyth_recorder_t old_rec) * * Scope: PUBLIC * * Description * * Set up the file information the recorder needs to watch live * tv. The recorder is supplied. This will be duplicated and * released, so the caller can re-use the same variable to hold the * return. The new copy of the recorder will have a livetv chain * within it. * * Return Value: * * Success: A pointer to a new recorder structure with a livetvchain * * Failure: NULL but the recorder passed in is not released the * caller needs to do this on a failure. */ cmyth_recorder_t cmyth_livetv_chain_setup(cmyth_recorder_t rec, int tcp_rcvbuf, void (*prog_update_callback)(cmyth_proginfo_t)) { cmyth_recorder_t new_rec = NULL; char url[1024]; cmyth_conn_t control; cmyth_proginfo_t loc_prog; cmyth_file_t ft; if (!rec) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: no recorder connection\n", __FUNCTION__); return NULL; } control = rec->rec_conn; /* Get the current recording information */ loc_prog = cmyth_recorder_get_cur_proginfo(rec); if (loc_prog == NULL) { cmyth_dbg(CMYTH_DBG_DEBUG, "%s: could not get current filename\n", __FUNCTION__); goto out; } pthread_mutex_lock(&mutex); new_rec = cmyth_recorder_dup(rec); if (new_rec == NULL) { cmyth_dbg(CMYTH_DBG_DEBUG, "%s: cannot create recorder\n", __FUNCTION__); goto out; } ref_release(rec); if(new_rec->rec_livetv_chain == NULL) { cmyth_dbg(CMYTH_DBG_DEBUG, "%s: error no livetv_chain\n", __FUNCTION__); new_rec = NULL; goto out; } sprintf(url, "myth://%s:%d%s", loc_prog->proginfo_hostname, rec->rec_port, loc_prog->proginfo_pathname); if(cmyth_livetv_chain_has_url(new_rec, url) == -1) { new_rec->rec_livetv_chain->livetv_tcp_rcvbuf = tcp_rcvbuf; ft = cmyth_conn_connect_file(loc_prog, new_rec->rec_conn, 4096, new_rec->rec_livetv_chain->livetv_tcp_rcvbuf); if (!ft) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_conn_connect_file(%s) failed\n", __FUNCTION__, url); new_rec = NULL; goto out; } } if(cmyth_livetv_chain_add(new_rec, url, ft, loc_prog) == -1) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_livetv_chain_add(%s) failed\n", __FUNCTION__, url); new_rec = NULL; ref_release(ft); goto out; } new_rec->rec_livetv_chain->prog_update_callback = prog_update_callback; ref_release(ft); /* JLB: Manage program breaks * Switch ON watch signal */ new_rec->rec_livetv_chain->livetv_watch = 1; cmyth_livetv_chain_switch(new_rec, 0); out: pthread_mutex_unlock(&mutex); ref_release(loc_prog); return new_rec; }
/* * cmyth_livetv_chain_setup(cmyth_recorder_t old_rec) * * Scope: PUBLIC * * Description * * Set up the file information the recorder needs to watch live * tv. The recorder is supplied. This will be duplicated and * released, so the caller can re-use the same variable to hold the * return. The new copy of the recorder will have a livetv chain * within it. * * Return Value: * * Success: A pointer to a new recorder structure with a livetvchain * * Failure: NULL but the recorder passed in is not released the * caller needs to do this on a failure. */ cmyth_recorder_t cmyth_livetv_chain_setup(cmyth_recorder_t rec, int tcp_rcvbuf, void (*prog_update_callback)(cmyth_proginfo_t)) { cmyth_recorder_t new_rec = NULL; char url[1024]; cmyth_conn_t control; cmyth_proginfo_t loc_prog, loc_prog2; cmyth_file_t ft; int i=0; if (!rec) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: no recorder connection\n", __FUNCTION__); return NULL; } control = rec->rec_conn; /* Get the current recording information */ loc_prog = cmyth_recorder_get_cur_proginfo(rec); /* Since backend will pretty much lockup when trying to open an * * empty file, like the dummy file first generated by dvd */ loc_prog2 = (cmyth_proginfo_t)ref_hold(loc_prog); while(i++<5 && (loc_prog2 == NULL || (loc_prog2 && loc_prog2->proginfo_Length == 0))) { usleep(200000); if(loc_prog2) ref_release(loc_prog2); loc_prog2 = cmyth_recorder_get_cur_proginfo(rec); loc_prog2 = cmyth_proginfo_get_detail(control, loc_prog2); } if (loc_prog == NULL) { cmyth_dbg(CMYTH_DBG_DEBUG, "%s: could not get current filename\n", __FUNCTION__); goto out; } pthread_mutex_lock(&mutex); sprintf(url, "myth://%s:%d%s",loc_prog->proginfo_hostname, rec->rec_port, loc_prog->proginfo_pathname); new_rec = cmyth_recorder_dup(rec); if (new_rec == NULL) { cmyth_dbg(CMYTH_DBG_DEBUG, "%s: cannot create recorder\n", __FUNCTION__); goto out; } ref_release(rec); if(new_rec->rec_livetv_chain == NULL) { cmyth_dbg(CMYTH_DBG_DEBUG, "%s: error no livetv_chain\n", __FUNCTION__); new_rec = NULL; goto out; } if(cmyth_livetv_chain_has_url(new_rec, url) == -1) { ft = cmyth_conn_connect_file(loc_prog, new_rec->rec_conn, 16*1024, tcp_rcvbuf); if (!ft) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_conn_connect_file(%s) failed\n", __FUNCTION__, url); new_rec = NULL; goto out; } if(cmyth_livetv_chain_add(new_rec, url, ft, loc_prog) == -1) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_livetv_chain_add(%s) failed\n", __FUNCTION__, url); new_rec = NULL; goto out; } new_rec->rec_livetv_chain->prog_update_callback = prog_update_callback; ref_release(ft); cmyth_livetv_chain_switch(new_rec, 0); } ref_release(loc_prog); out: pthread_mutex_unlock(&mutex); return new_rec; }
/* * cmyth_ringbuf_setup(cmyth_recorder_t old_rec) * * Scope: PUBLIC * * Description * * Set up the ring buffer inside a recorder for use in playing live * tv. The recorder is supplied. This will be duplicated and * released, so the caller can re-use the same variable to hold the * return. The new copy of the recorder will have a ringbuffer set up * within it. * * Return Value: * * Success: A pointer to a new recorder structure with a ringbuffer * * Faiure: NULL */ cmyth_recorder_t cmyth_ringbuf_setup(cmyth_recorder_t rec) { static const char service[]="rbuf://"; cmyth_recorder_t new_rec = NULL; char *host = NULL; char *port = NULL; char *path = NULL; char tmp; int err, count; int r; long long size, fill; char msg[256]; char url[1024]; char buf[32]; cmyth_conn_t control; if (!rec) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: no recorder connection\n", __FUNCTION__); return NULL; } control = rec->rec_conn; pthread_mutex_lock(&mutex); snprintf(msg, sizeof(msg), "QUERY_RECORDER %u[]:[]SETUP_RING_BUFFER[]:[]0", rec->rec_id); if ((err=cmyth_send_message(control, msg)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_send_message() failed (%d)\n", __FUNCTION__, err); goto out; } count = cmyth_rcv_length(control); if (control->conn_version >= 16) { r = cmyth_rcv_string(control, &err, buf, sizeof(buf)-1, count); count -= r; } r = cmyth_rcv_string(control, &err, url, sizeof(url)-1, count); count -= r; if ((r=cmyth_rcv_long_long(control, &err, &size, count)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_length() failed (%d)\n", __FUNCTION__, r); goto out; } count -= r; if ((r=cmyth_rcv_long_long(control, &err, &fill, count)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_length() failed (%d)\n", __FUNCTION__, r); goto out; } cmyth_dbg(CMYTH_DBG_DEBUG, "%s: url is: '%s'\n", __FUNCTION__, url); path = url; if (strncmp(url, service, sizeof(service) - 1) == 0) { /* * The URL starts with rbuf://. The rest looks like * <host>:<port>/<filename>. */ host = url + strlen(service); port = strchr(host, ':'); if (!port) { /* * This does not seem to be a proper URL, so just * assume it is a filename, and get out. */ cmyth_dbg(CMYTH_DBG_DEBUG, "%s: 1 port %s, host = %s\n", __FUNCTION__, port, host); goto out; } port = port + 1; path = strchr(port, '/'); if (!path) { /* * This does not seem to be a proper URL, so just * assume it is a filename, and get out. */ cmyth_dbg(CMYTH_DBG_DEBUG, "%s: no path\n", __FUNCTION__); goto out; } } new_rec = cmyth_recorder_dup(rec); if (new_rec == NULL) { cmyth_dbg(CMYTH_DBG_DEBUG, "%s: cannot create recorder\n", __FUNCTION__); goto out; } ref_release(rec); new_rec->rec_ring = cmyth_ringbuf_create(); tmp = *(port - 1); *(port - 1) = '\0'; new_rec->rec_ring->ringbuf_hostname = ref_strdup(host); *(port - 1) = tmp; tmp = *(path); *(path) = '\0'; new_rec->rec_ring->ringbuf_port = atoi(port); *(path) = tmp; new_rec->rec_ring->ringbuf_url = ref_strdup(url); new_rec->rec_ring->ringbuf_size = size; new_rec->rec_ring->ringbuf_fill = fill; out: pthread_mutex_unlock(&mutex); return new_rec; }