int cmyth_rcv_commbreaklist(cmyth_conn_t conn, int *err, cmyth_commbreaklist_t breaklist, int count) { int consumed; int total = 0; long rows; char *failed = NULL; cmyth_commbreak_t commbreak; unsigned short type; int i; int j; if (count <= 0) { *err = EINVAL; return 0; } /* * Get number of rows */ consumed = cmyth_rcv_long(conn, err, &rows, count); count -= consumed; total += consumed; if (*err) { failed = "cmyth_rcv_long"; goto fail; } if (rows < 0) { cmyth_dbg(CMYTH_DBG_DEBUG, "%s: no commercial breaks found.\n", __FUNCTION__); return 0; } else { /* * Don't check for an uneven row count. mythcommflag can mark the start of the last * commercial break, but then not mark the end before it reaches the end of the file. * For this case the last commercial break is ignored. */ breaklist->commbreak_count = rows / 2; } breaklist->commbreak_list = malloc(breaklist->commbreak_count * sizeof(cmyth_commbreak_t)); if (!breaklist->commbreak_list) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: malloc() failed for list\n", __FUNCTION__); *err = ENOMEM; return consumed; } memset(breaklist->commbreak_list, 0, breaklist->commbreak_count * sizeof(cmyth_commbreak_t)); for (i = 0; i < breaklist->commbreak_count; i++) { commbreak = cmyth_commbreak_create(); for (j = 0; j < 2; j++) { consumed = cmyth_rcv_ushort(conn, err, &type, count); count -= consumed; total += consumed; if (*err) { failed = "cmyth_rcv_ushort"; goto fail; } /* * Do a little sanity-checking. */ if (j == 0 && type != CMYTH_COMMBREAK_START) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: type was not CMYTH_COMMBREAK_START\n", __FUNCTION__); return 0; } else if (j == 1 && type != CMYTH_COMMBREAK_END) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: type was not CMYTH_COMMBREAK_END\n", __FUNCTION__); return 0; } /* * Only marks are returned, not the offsets. Marks are encoded in long_long. */ if (j == 0) { consumed = cmyth_rcv_long_long(conn, err, &commbreak->start_mark, count); } else { consumed = cmyth_rcv_long_long(conn, err, &commbreak->end_mark, count); } count -= consumed; total += consumed; if (*err) { failed = "cmyth_rcv_long"; goto fail; } } breaklist->commbreak_list[i] = commbreak; } return total; fail: cmyth_dbg(CMYTH_DBG_ERROR, "%s: %s() failed (%d)\n", __FUNCTION__, failed, *err); return total; }
int cmyth_conn_get_freespace(cmyth_conn_t control, long long *total, long long *used) { int err, count, ret = 0; int r; char msg[256]; char reply[256]; long long lreply; if (control == NULL) return -EINVAL; if ((total == NULL) || (used == NULL)) return -EINVAL; pthread_mutex_lock(&mutex); if (control->conn_version >= 32) { snprintf(msg, sizeof(msg), "QUERY_FREE_SPACE_SUMMARY"); } else if (control->conn_version >= 17) { snprintf(msg, sizeof(msg), "QUERY_FREE_SPACE"); } else { snprintf(msg, sizeof(msg), "QUERY_FREESPACE"); } if ((err = cmyth_send_message(control, msg)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_send_message() failed (%d)\n", __FUNCTION__, err); ret = err; goto out; } if ((count=cmyth_rcv_length(control)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_length() failed (%d)\n", __FUNCTION__, count); ret = count; goto out; } if (control->conn_version >= 17) { if ((r=cmyth_rcv_long_long(control, &err, &lreply, count)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_long_long() failed (%d)\n", __FUNCTION__, err); ret = err; goto out; } *total = lreply; if ((r=cmyth_rcv_long_long(control, &err, &lreply, count-r)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_long_long() failed (%d)\n", __FUNCTION__, err); ret = err; goto out; } *used = lreply; } else { if ((r=cmyth_rcv_string(control, &err, reply, sizeof(reply)-1, count)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed (%d)\n", __FUNCTION__, err); ret = err; goto out; } *total = atoi(reply); if ((r=cmyth_rcv_string(control, &err, reply, sizeof(reply)-1, count-r)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed (%d)\n", __FUNCTION__, err); ret = err; goto out; } *used = atoi(reply); *used *= 1024; *total *= 1024; } out: pthread_mutex_unlock(&mutex); return ret; }
/* * cmyth_file_seek(cmyth_file_t file, long long offset, int whence) * * Scope: PUBLIC * * Description * * Seek to a new position in the file based on the value of whence: * SEEK_SET * The offset is set to offset bytes. * SEEK_CUR * The offset is set to the current position plus offset bytes. * SEEK_END * The offset is set to the size of the file minus offset bytes. * * Return Value: * * Sucess: 0 * * Failure: an int containing -errno */ long long cmyth_file_seek(cmyth_file_t file, long long offset, int whence) { char msg[128]; int err; int count; long long c; long r; long long ret; if (file == NULL) return -EINVAL; if ((offset == 0) && (whence == SEEK_CUR)) return file->file_pos; pthread_mutex_lock(&mutex); snprintf(msg, sizeof(msg), "QUERY_FILETRANSFER %ld[]:[]SEEK[]:[]%d[]:[]%d[]:[]%d[]:[]%d[]:[]%d", file->file_id, (int32_t)(offset >> 32), (int32_t)(offset & 0xffffffff), whence, (int32_t)(file->file_pos >> 32), (int32_t)(file->file_pos & 0xffffffff)); if ((err = cmyth_send_message(file->file_control, msg)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_send_message() failed (%d)\n", __FUNCTION__, err); ret = err; goto out; } if ((count=cmyth_rcv_length(file->file_control)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_length() failed (%d)\n", __FUNCTION__, count); ret = count; goto out; } if ((r=cmyth_rcv_long_long(file->file_control, &err, &c, count)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_long_long() failed (%d)\n", __FUNCTION__, r); ret = err; goto out; } switch (whence) { case SEEK_SET: file->file_pos = offset; break; case SEEK_CUR: file->file_pos += offset; break; case SEEK_END: file->file_pos = file->file_length - offset; break; } ret = file->file_pos; out: pthread_mutex_unlock(&mutex); return ret; }
/* * cmyth_ringbuf_seek( * cmyth_ringbuf_t file, long long offset, int whence) * * Scope: PUBLIC * * Description * * Seek to a new position in the file based on the value of whence: * SEEK_SET * The offset is set to offset bytes. * SEEK_CUR * The offset is set to the current position plus offset bytes. * SEEK_END * The offset is set to the size of the file minus offset bytes. * * Return Value: * * Sucess: 0 * * Failure: an int containing -errno */ long long cmyth_ringbuf_seek(cmyth_recorder_t rec, long long offset, int whence) { char msg[128]; int err; int count; long long c; long r; long long ret; cmyth_ringbuf_t ring; if (rec == NULL) return -EINVAL; ring = rec->rec_ring; if ((offset == 0) && (whence == SEEK_CUR)) return ring->file_pos; pthread_mutex_lock(&mutex); snprintf(msg, sizeof(msg), "QUERY_RECORDER %u[]:[]SEEK_RINGBUF[]:[]%d[]:[]%d[]:[]%d[]:[]%d[]:[]%d", rec->rec_id, (int32_t)(offset >> 32), (int32_t)(offset & 0xffffffff), whence, (int32_t)(ring->file_pos >> 32), (int32_t)(ring->file_pos & 0xffffffff)); if ((err = cmyth_send_message(rec->rec_conn, msg)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_send_message() failed (%d)\n", __FUNCTION__, err); ret = err; goto out; } count = cmyth_rcv_length(rec->rec_conn); if ((r=cmyth_rcv_long_long(rec->rec_conn, &err, &c, count)) < 0) { cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_length() failed (%d)\n", __FUNCTION__, r); ret = err; goto out; } switch (whence) { case SEEK_SET: ring->file_pos = offset; break; case SEEK_CUR: ring->file_pos += offset; break; case SEEK_END: ring->file_pos = ring->file_length - offset; break; } ret = ring->file_pos; out: pthread_mutex_unlock(&mutex); return ret; }
/* * 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; }
int cmyth_rcv_commbreaklist(cmyth_conn_t conn, int *err, cmyth_commbreaklist_t breaklist, int count) { int consumed; int total = 0; long rows; long long mark; long long start = -1; char *failed = NULL; cmyth_commbreak_t commbreak; unsigned short type; unsigned short start_type; int i; int j; if (count <= 0) { *err = EINVAL; return 0; } /* * Get number of rows */ consumed = cmyth_rcv_long(conn, err, &rows, count); count -= consumed; total += consumed; if (*err) { failed = "cmyth_rcv_long"; goto fail; } if (rows < 0) { cmyth_dbg(CMYTH_DBG_DEBUG, "%s: no commercial breaks found.\n", __FUNCTION__); return 0; } for (i = 0; i < rows; i++) { consumed = cmyth_rcv_ushort(conn, err, &type, count); count -= consumed; total += consumed; if (*err) { failed = "cmyth_rcv_ushort"; goto fail; } consumed = cmyth_rcv_long_long(conn, err, &mark, count); count -= consumed; total += consumed; if (*err) { failed = "cmyth_rcv_long long"; goto fail; } if (type == CMYTH_COMMBREAK_START || type == CMYTH_CUTLIST_START) { start = mark; start_type = type; } else if (type == CMYTH_COMMBREAK_END || type == CMYTH_CUTLIST_END) { if (start >= 0 && (type == CMYTH_COMMBREAK_END && start_type == CMYTH_COMMBREAK_START || type == CMYTH_CUTLIST_END && start_type == CMYTH_CUTLIST_START)) { commbreak = cmyth_commbreak_create(); commbreak->start_mark = start; commbreak->end_mark = mark; start = -1; breaklist->commbreak_list = realloc(breaklist->commbreak_list, (++breaklist->commbreak_count) * sizeof(cmyth_commbreak_t)); breaklist->commbreak_list[breaklist->commbreak_count - 1] = commbreak; } else { cmyth_dbg(CMYTH_DBG_WARN, "%s: ignoring 'end' marker without a 'start' marker at %lld\n", __FUNCTION__, type, mark); } } else { cmyth_dbg(CMYTH_DBG_WARN, "%s: type (%d) is not a COMMBREAK or CUTLIST\n", __FUNCTION__, type); } } /* * If the last entry is a start marker then it doesn't have an associated end marker. In this * case we choose to simply ignore it. Another option is to put in a really large fake end marker * but that may cause strange seek behaviour in a client application. */ return total; fail: cmyth_dbg(CMYTH_DBG_ERROR, "%s: %s() failed (%d)\n", __FUNCTION__, failed, *err); return total; }