All its parameters are known globally within vss.c, so omit them.
Also, return an int instead of the pointer to the inbuffer which is
also known to the caller.
This patch also introduces para_fseek() in fd.c which is used by
mp3.c and vss.c and changes the mp3 audio format handler so that it
uses the new function and always check the return value.
#define MP3_AFH_ERRORS \
- PARA_ERROR(FREAD, "fread error"), \
- PARA_ERROR(FSEEK, "fseek error"), \
PARA_ERROR(FRAME, "invalid mp3 frame"), \
PARA_ERROR(FRAME_LENGTH, "invalid frame length"), \
PARA_ERROR(MP3_NO_FILE, "invalid mp3 file pointer"), \
#define VSS_ERRORS \
PARA_ERROR(AUDIO_FORMAT, "audio format not recognized"), \
PARA_ERROR(FSTAT, "failed to fstat() audio file"), \
+ PARA_ERROR(EMPTY_CHUNK, "empty chunk"), \
#define AFS_ERRORS \
PARA_ERROR(F_GETFL, "failed to get fd flags"), \
PARA_ERROR(F_SETFL, "failed to set fd flags"), \
PARA_ERROR(FGETS, "fgets error"), \
+ PARA_ERROR(FSEEK, "fseek error"), \
+ PARA_ERROR(FREAD, "fread error"), \
#define WRITE_ERRORS \
return -E_FREAD;
}
/**
-* paraslash's wrapper for fgets(3)
+* paraslash's wrapper for fgets(3)
* \param line pointer to the buffer to store the line
* \param size the size of the buffer given by \a line
* \param f the stream to read from
clearerr(f);
goto again;
}
+
+int para_fseek(FILE *stream, long offset, int whence)
+{
+ int ret = fseek(stream, offset, whence);
+ return ret < 0? -E_FSEEK : ret;
+}
__must_check int para_fread(void *dest, size_t nbytes, size_t nmemb,
FILE *stream);
__must_check int para_fgets(char *line, int size, FILE *f);
+int para_fseek(FILE *stream, long offset, int whence);
*/
static int mp3_seek_next_header(void)
{
- int k, l = 0, c, first_len;
+ int k, l = 0, c, first_len, ret;
struct mp3header h, h2;
long valid_start = 0;
first_len = get_header(infile, &h);
if (first_len <= 0)
continue;
- if (fseek(infile, first_len - FRAME_HEADER_SIZE, SEEK_CUR) < 0)
- return -E_FSEEK;
+ ret = para_fseek(infile, first_len - FRAME_HEADER_SIZE, SEEK_CUR);
+ if (ret < 0)
+ return ret;
for (k = 1; k < MIN_CONSEC_GOOD_FRAMES; k++) {
if ((l = get_header(infile, &h2)) <= 0)
break;
if (!compare_headers(&h, &h2))
break;
- fseek(infile, l - FRAME_HEADER_SIZE, SEEK_CUR);
+ ret = para_fseek(infile, l - FRAME_HEADER_SIZE, SEEK_CUR);
+ if (ret < 0)
+ return ret;
}
if (k == MIN_CONSEC_GOOD_FRAMES) {
- fseek(infile, valid_start, SEEK_SET);
+ ret = para_fseek(infile, valid_start, SEEK_SET);
+ if (ret < 0)
+ return ret;
memcpy(&(mp3.header), &h2, sizeof(struct mp3header));
return first_len;
}
static int mp3_get_id3(void)
{
char fbuf[4];
+ int ret;
mp3.id3_isvalid = 0;
mp3.id3.title[0] = '\0';
mp3.id3.album[0] = '\0';
mp3.id3.comment[0] = '\0';
mp3.id3.year[0] = '\0';
- if (fseek(infile, -128, SEEK_END))
- return -E_FSEEK;
+ ret = para_fseek(infile, -128, SEEK_END);
+ if (ret < 0 )
+ return ret;
if (para_fread(fbuf, 1, 3, infile) < 0)
return -E_FREAD;
fbuf[3] = '\0';
PARA_INFO_LOG("%s", "no id3 tag\n");
return 0;
}
- if (fseek(infile, -125, SEEK_END) < 0)
- return -E_FSEEK;
+ ret = para_fseek(infile, -125, SEEK_END);
+ if (ret < 0)
+ return ret;
if (para_fread(mp3.id3.title, 1, 30, infile) != 30)
return -E_FREAD;
mp3.id3.title[30] = '\0';
static int find_valid_start(void)
{
- int frame_len;
+ int ret, frame_len;
if (!infile)
return -E_MP3_NO_FILE;
frame_len = mp3_seek_next_header();
if (frame_len <= 0)
return frame_len;
- } else
- if (fseek(infile, -FRAME_HEADER_SIZE, SEEK_CUR) < 0)
- return -E_FSEEK;
+ } else {
+ ret = para_fseek(infile, -FRAME_HEADER_SIZE, SEEK_CUR);
+ if (ret < 0)
+ return ret;
+ }
if (frame_len <= 1)
return -E_FRAME_LENGTH;
return frame_len;
int freq, br, fl;
struct timeval tmp, cct; /* current chunk time */
if (len > 0) {
- ret = -E_FSEEK;
- if (fseek(infile, len, SEEK_CUR) < 0)
+ ret = para_fseek(infile, len, SEEK_CUR);
+ if (ret < 0)
goto err_out;
}
len = find_valid_start();
ret = -E_MP3_INFO;
if (!num_chunks || !freq_avg || !br_avg)
goto err_out;
- ret = -E_FSEEK;
- if (fseek(infile, 0, SEEK_END) < 0)
+ ret= para_fseek(infile, 0, SEEK_END);
+ if (ret < 0)
goto err_out;
chunk_table[num_chunks] = ftell(infile);
mp3.br_average = br_avg;
return ret;
}
-static char *vss_read_chunk(long unsigned current_chunk, ssize_t *len)
+/**
+ * read a chunk of data from the current audio file
+ *
+ * \param current_chunk the chunk number to read
+ *
+ * \return The length of the chunk on success, zero on end of file, negative on
+ * errors. Note: If the current chunk is of length zero, but the end of the
+ * file is not yet reached, this function returns -E_EMPTY_CHUNK.
+ * */
+ssize_t vss_read_chunk(void)
{
- int ret;
+ ssize_t len;
size_t pos;
-
- *len = 0;
- if (current_chunk >= mmd->chunks_total)
- return NULL;
- *len = chunk_table[current_chunk + 1] - chunk_table[current_chunk];
- if (!*len) /* nothing to send for this run */
- return inbuf;
- pos = chunk_table[current_chunk];
- if (inbuf_size < *len) {
- PARA_INFO_LOG("increasing inbuf for chunk #%lu/%lu to %zd bytes\n",
- current_chunk, mmd->chunks_total, *len);
- inbuf = para_realloc(inbuf, *len);
- inbuf_size = *len;
+ int ret;
+ long unsigned cc = mmd->current_chunk;
+
+ if (cc >= mmd->chunks_total) /* eof */
+ return 0;
+ len = chunk_table[cc + 1] - chunk_table[cc];
+ if (!len) /* nothing to send for this run */
+ return -E_EMPTY_CHUNK;
+ pos = chunk_table[cc];
+ if (inbuf_size < len) {
+ PARA_INFO_LOG("increasing inbuf for chunk #%lu/%lu to %zu bytes\n",
+ cc, mmd->chunks_total, len);
+ inbuf = para_realloc(inbuf, len);
+ inbuf_size = len;
}
-// PARA_DEBUG_LOG("reading chunk #%lu@%zd (%zd bytes)\n", current_chunk,
-// pos, *len);
- ret = fseek(audio_file, pos, SEEK_SET);
+ ret = para_fseek(audio_file, pos, SEEK_SET);
if (ret < 0)
- return NULL;
- ret = para_fread(inbuf, *len, 1, audio_file);
- if (ret != *len)
- return NULL;
- return inbuf;
+ return ret;
+ return para_fread(inbuf, len, 1, audio_file);
}
/**
{
int i;
struct audio_format_handler *af;
- char *buf;
ssize_t ret;
struct timeval now, due;
if (chk_barrier("data send", &now, &data_send_barrier,
&due, 1) < 0)
return;
- buf = vss_read_chunk(mmd->current_chunk, &ret);
+ ret= vss_read_chunk();
mmd->new_vss_status_flags &= ~VSS_REPOS;
- if (!buf) {
- if (ret < 0)
+ if (!ret || (ret < 0 && ret != -E_EMPTY_CHUNK)) {
+ if (ret < 0) {
mmd->new_vss_status_flags = VSS_NEXT;
- else
+ PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+ } else
mmd->new_vss_status_flags |= VSS_NEXT;
vss_eof(af);
return;
}
+ /*
+ * We call the send function also in case of empty chunks as they
+ * might have still some data queued which can be sent in this case.
+ */
+ if (ret < 0)
+ ret = 0;
if (!mmd->chunks_sent) {
struct timeval tmp;
gettimeofday(&mmd->stream_start, NULL);
mmd->events++;
}
for (i = 0; senders[i].name; i++)
- senders[i].send(mmd->current_chunk, mmd->chunks_sent, buf, ret);
+ senders[i].send(mmd->current_chunk, mmd->chunks_sent, inbuf, ret);
mmd->new_vss_status_flags |= VSS_PLAYING;
mmd->chunks_sent++;
mmd->current_chunk++;