/* * cmyth_livetv_wait() * * After starting live TV or after a channel change wait here until some * recording data is available. */ static int cmyth_livetv_wait(cmyth_recorder_t rec) { int i = 0, rc = -1; cmyth_conn_t conn; static int failures = 0; usleep(250000*failures); conn = cmyth_conn_reconnect(rec->rec_conn); while (i++ < 10) { int len; cmyth_proginfo_t prog; cmyth_file_t file; if (!cmyth_recorder_is_recording(rec)) { usleep(1000); continue; } prog = cmyth_recorder_get_cur_proginfo(rec); if (prog == NULL) { usleep(1000); continue; } file = cmyth_conn_connect_file(prog, conn, 4096, 4096); ref_release(prog); if (file == NULL) { if (failures < 4) { failures++; } usleep(1000); continue; } len = cmyth_file_request_block(file, 512); ref_release(file); if (len == 512) { rc = 0; break; } if (failures < 4) { failures++; } usleep(1000); } ref_release(conn); return rc; }
/* * 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_livetv_chain_update(cmyth_recorder_t rec, char * chainid, int buff) * * Scope: PUBLIC * * Description * * Called in response to the backend's notification of a chain update. * The recorder is supplied and will be queried for the current recording * to determine if a new file needs to be added to the chain of files * in the live tv instance. * * Return Value: * * Success: 0 * * Failure: -1 */ int cmyth_livetv_chain_update(cmyth_recorder_t rec, char * chainid, int tcp_rcvbuf) { int ret=0; char url[1024]; cmyth_conn_t control; cmyth_proginfo_t loc_prog; cmyth_file_t ft; if (!rec) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: rec is NULL\n", __FUNCTION__); goto out; } control = rec->rec_conn; loc_prog = cmyth_recorder_get_cur_proginfo(rec); pthread_mutex_lock(&mutex); if(rec->rec_livetv_chain) { if(strncmp(rec->rec_livetv_chain->chainid, chainid, strlen(chainid)) == 0) { sprintf(url, "myth://%s:%d%s",loc_prog->proginfo_hostname, rec->rec_port, loc_prog->proginfo_pathname); /* Now check if this file is in the recorder chain and if not then open a new file transfer and add it to the chain. */ if(cmyth_livetv_chain_has_url(rec, url) == -1) { ft = cmyth_conn_connect_file(loc_prog, rec->rec_conn, 16*1024, tcp_rcvbuf); if (!ft) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_conn_connect_file(%s) failed\n", __FUNCTION__, url); ret = -1; goto out; } if(cmyth_livetv_chain_add(rec, url, ft, loc_prog) == -1) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_livetv_chain_add(%s) failed\n", __FUNCTION__, url); ret = -1; goto out; } ref_release(ft); if(rec->rec_livetv_chain->chain_switch_on_create) { cmyth_livetv_chain_switch(rec, LAST); rec->rec_livetv_chain->chain_switch_on_create = 0; } } } else { cmyth_dbg(CMYTH_DBG_ERROR, "%s: chainid doesn't match recorder's chainid!!\n", __FUNCTION__, url); ret = -1; } } else { cmyth_dbg(CMYTH_DBG_ERROR, "%s: rec_livetv_chain is NULL!!\n", __FUNCTION__, url); ret = -1; } ref_release(loc_prog); out: pthread_mutex_unlock(&mutex); return ret; }
int cmyth_recorder_add_chanlist(cmyth_recorder_t rec) { cmyth_proginfo_t zero, first, prog; char *first_name; cmyth_chanlist_t list; cmyth_channel_t channel; /* * Get a list of channels for the recorder by cycling through the * current program guide. For some reason, the first proginfo * structure retrieved seems to be empty, so just ignore it. */ zero = cmyth_recorder_get_cur_proginfo(rec); if (zero == NULL) { return -1; } first = cmyth_recorder_get_next_proginfo(rec, zero, BROWSE_DIRECTION_UP); ref_release(zero); first_name = cmyth_proginfo_channame(first); prog = ref_hold(first); list = cmyth_chanlist_create(); while (1) { cmyth_proginfo_t prev = prog; char *name, *sign, *icon; char buf[128]; prog = cmyth_recorder_get_next_proginfo(rec, prev, BROWSE_DIRECTION_UP); if (prog == NULL) { break; } name = cmyth_proginfo_channame(prog); sign = cmyth_proginfo_chansign(prog); snprintf(buf, sizeof(buf), "%s %s", name, sign); icon = cmyth_proginfo_chanicon(prog); channel = cmyth_channel_create(prog->proginfo_chanId, name, sign, buf, icon); cmyth_chanlist_add(list, channel); ref_release(channel); ref_release(sign); ref_release(icon); ref_release(prev); if (strcmp(first_name, name) == 0) { ref_release(name); break; } ref_release(name); } rec->rec_chanlist = list; ref_release(first_name); ref_release(first); ref_release(prog); return 0; }
/* * 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_update(cmyth_recorder_t rec, char * chainid, int buff) * * Scope: PUBLIC * * Description * * Called in response to the backend's notification of a chain update. * The recorder is supplied and will be queried for the current recording * to determine if a new file needs to be added to the chain of files * in the live tv instance. * * Return Value: * * Success: 0 * * Failure: -1 */ int cmyth_livetv_chain_update(cmyth_recorder_t rec, char * chainid) { int ret; char url[1024]; cmyth_proginfo_t loc_prog; cmyth_file_t ft; ret = 0; if (!rec) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: rec is NULL\n", __FUNCTION__); return -1; } /* JLB: Manage program break * Skip chain update, it will doing later */ if (!rec->rec_livetv_chain) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: rec_livetv_chain is NULL\n", __FUNCTION__, url); return -1; } else { if (rec->rec_livetv_chain->livetv_watch != 1) { cmyth_dbg(CMYTH_DBG_DEBUG, "%s: skip chain update\n", __FUNCTION__); return 0; } } loc_prog = cmyth_recorder_get_cur_proginfo(rec); if (!loc_prog) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: recorder is not recording\n", __FUNCTION__); return -1; } pthread_mutex_lock(&mutex); if (strncmp(rec->rec_livetv_chain->chainid, chainid, strlen(chainid)) == 0) { sprintf(url, "myth://%s:%d%s", loc_prog->proginfo_hostname, rec->rec_port, loc_prog->proginfo_pathname); /* Now check if this file is in the recorder chain and if not then open a new file transfer and add it to the chain. */ if (cmyth_livetv_chain_has_url(rec, url) == -1) { ft = cmyth_conn_connect_file(loc_prog, rec->rec_conn, 4096, rec->rec_livetv_chain->livetv_tcp_rcvbuf); if (!ft) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_conn_connect_file(%s) failed\n", __FUNCTION__, url); ret = -1; goto out; } if (cmyth_livetv_chain_add(rec, url, ft, loc_prog) == -1) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_livetv_chain_add(%s) failed\n", __FUNCTION__, url); ret = -1; ref_release(ft); goto out; } ref_release(ft); if (rec->rec_livetv_chain->chain_switch_on_create) { cmyth_livetv_chain_switch(rec, LAST); rec->rec_livetv_chain->chain_switch_on_create = 0; } } } else { cmyth_dbg(CMYTH_DBG_ERROR, "%s: chainid doesn't match recorder's chainid!!\n", __FUNCTION__, url); ret = -1; } out: pthread_mutex_unlock(&mutex); ref_release(loc_prog); return ret; }
static void cmyth_chain_update(cmyth_chain_t chain, cmyth_recorder_t rec, char *msg) { char *p; cmyth_proginfo_t prog = NULL; cmyth_chain_entry_t entry; int size, tip; long long offset; int start = 0; char *path; if ((p=strchr(msg, ' ')) != NULL) { *(p++) = '\0'; if (strcmp(msg, "LIVETV_CHAIN UPDATE") != 0) { return; } } else { p = msg; } prog = cmyth_recorder_get_cur_proginfo(rec); if (prog == NULL) { return; } path = cmyth_proginfo_pathname(prog); if (path == NULL) { return; } if (strlen(path) == 0) { ref_release(path); ref_release(prog); return; } ref_release(path); pthread_mutex_lock(&chain->chain_mutex); if (!chain->chain_id || (strncmp(p, chain->chain_id, strlen(p)) != 0)) { goto out; } tip = chain->chain_count - 1; if (tip >= 0) { path = cmyth_proginfo_pathname(chain->chain_list[tip]->prog); ref_release(path); if (cmyth_proginfo_compare(prog, chain->chain_list[tip]->prog) == 0) { ref_release(prog); goto out; } offset = chain->chain_list[tip]->offset + cmyth_proginfo_length(chain->chain_list[tip]->prog); } else { offset = 0; start = 1; } size = sizeof(*chain->chain_list) * (++chain->chain_count); chain->chain_list = ref_realloc(chain->chain_list, size); entry = ref_alloc(sizeof(*entry)); entry->prog = prog; entry->file = NULL; entry->offset = offset; chain->chain_list[tip+1] = entry; pthread_cond_broadcast(&chain->chain_cond); out: pthread_mutex_unlock(&chain->chain_mutex); if (start) { chain->chain_current = 0; cmyth_chain_switch(chain, 0); } }
static int get_recorders(int level) { int i, j; for (i=0; i<=32; i++) { cmyth_recorder_t rec; int state; rec = cmyth_conn_get_recorder(control, i); if (rec == NULL) { continue; } state = cmyth_recorder_is_recording(rec); if (state == 0) { printf("Recorder %d is idle\n", i); } else if (state == 1) { cmyth_proginfo_t prog; cmyth_timestamp_t end; char str[32]; char *title; prog = cmyth_recorder_get_cur_proginfo(rec); end = cmyth_proginfo_rec_end(prog); cmyth_timestamp_to_string(str, end); printf("Recorder %d is recording until %s\n", i, str); if (prog && (level > 0)) { title = cmyth_proginfo_title(prog); if (title) { printf("\tTitle: %s\n", title); } ref_release(title); } ref_release(prog); ref_release(end); } else { printf("Recorder %d is in an unknown state\n", i); } if (level > 1) { cmyth_chanlist_t cl; cmyth_channel_t chan; char *name; cl = cmyth_recorder_get_chanlist(rec); for (j=0; j<cmyth_chanlist_get_count(cl); j++) { chan = cmyth_chanlist_get_item(cl, j); name = cmyth_channel_string(chan); printf("\tChannel: %s\n", name); ref_release(name); ref_release(chan); } ref_release(cl); } ref_release(rec); } return 0; }