/**
* the list of supported audio formats
*/
-struct audio_format_handler afl[] = {
+static struct audio_format_handler afl[] = {
#if 1
{
.name = "mp3",
.name = NULL,
}
};
-
+#define FOR_EACH_AUDIO_FORMAT(i) for (i = 0; afl[i].name; i++)
/**
* check if audio file sender is playing
&mmd->chunks_total, &mmd->seconds_total);
}
-/*
+/**
* guess the audio format judging from filename
+ *
* \param name the filename
*
* \return This function returns -1 if it has no idea what kind of audio
* file this might be. Otherwise the (non-negative) number of the audio format
* is returned.
*/
-static int guess_audio_format(const char *name)
+int guess_audio_format(const char *name)
{
-
- int i, len1 = strlen(name), len2;
-
- for (i = 0; afl[i].name; i++) {
- len2 = strlen(afl[i].name);
- if (len1 < len2)
- continue;
- if (!strncasecmp(name + (len1 - len2), afl[i].name, len2)) {
- PARA_DEBUG_LOG("might be %s\n", afl[i].name);
+ int i,j, len = strlen(name);
+
+ FOR_EACH_AUDIO_FORMAT(i) {
+ for (j = 0; afl[i].suffixes[j]; j++) {
+ const char *p = afl[i].suffixes[j];
+ int plen = strlen(p);
+ if (len < plen + 1)
+ continue;
+ if (name[len - plen - 1] != '.')
+ continue;
+ if (strcasecmp(name + len - plen, p))
+ continue;
+ PARA_DEBUG_LOG("might be %s\n", audio_format_name(i));
return i;
}
}
{
int i;
- for (i = 0; afl[i].name; i++) {
+ FOR_EACH_AUDIO_FORMAT(i) {
if (i == omit || !afl[i].get_file_info)
continue;
rewind(audio_file);
mmd->events++;
}
+/**
+ * get the header and of the current audio file
+ *
+ * \param header_len the length of the header is stored here
+ *
+ * \return a pointer to a buffer containing the header, or NULL, if no audio
+ * file is selected or if the current audio format does not need special header
+ * treamtment.
+ *
+ */
+char *afs_get_header(int *header_len)
+{
+ *header_len = 0;
+ if (mmd->audio_format < 0)
+ return NULL;
+ if (!afl[mmd->audio_format].get_header_info)
+ return NULL;
+ return afl[mmd->audio_format].get_header_info(header_len);
+}
+
+/**
+ * get the chunk time of the current audio file
+ *
+ * \return a pointer to a struct containing the chunk time, or NULL,
+ * if currently no audio file is selected.
+ */
+struct timeval *afs_chunk_time(void)
+{
+ if (mmd->audio_format < 0)
+ return NULL;
+ return &afl[mmd->audio_format].chunk_tv;
+}
+
/**
* compute the timeout for para_server's main select-loop
*
mmd->events++;
}
for (i = 0; senders[i].name; i++)
- senders[i].send(af, mmd->current_chunk,
- mmd->chunks_sent, buf, ret);
+ senders[i].send(mmd->current_chunk, mmd->chunks_sent, buf, ret);
mmd->new_afs_status_flags |= AFS_PLAYING;
mmd->chunks_sent++;
mmd->current_chunk++;
char * (*read_chunk)(long unsigned chunk_num, ssize_t *len);
};
-extern struct audio_format_handler afl[];
-#define FOR_EACH_AUDIO_FORMAT(i) for (i = 0; afl[i].name; i++)
void afs_init(void);
void afs_send_chunk(void);
unsigned int afs_next(void);
unsigned int afs_repos(void);
unsigned int afs_paused(void);
-
+char *afs_get_header(int *header_len);
+struct timeval *afs_chunk_time(void);
+int guess_audio_format(const char *name);
return;
}
if (s->write_fd > 0) {
+ PARA_INFO_LOG("err: %d\n", s->fci->error);
PARA_INFO_LOG("slot %d: closing write fd %d\n", slot_num,
s->write_fd);
close(s->write_fd);
#include "error.h"
#include "string.h"
-/*
- * return 1 if name matches any supported audio format
- */
-static int match_audio_file_name(char *name)
-{
- int i,j, len = strlen(name);
-
- FOR_EACH_AUDIO_FORMAT(i) {
- for (j = 0; afl[i].suffixes[j]; j++) {
- const char *p = afl[i].suffixes[j];
- int plen = strlen(p);
- if (len < plen + 1)
- continue;
- if (name[len - plen - 1] != '.')
- continue;
- if (strcasecmp(name + len - plen, p))
- continue;
- return 1;
- }
- }
- return 0;
-}
-
/**
* traverse the given directory recursively
*
if (!S_ISREG(m) && !S_ISDIR(m)) /* skip links, sockets, ... */
continue;
if (S_ISREG(m)) { /* regular file */
- if (!match_audio_file_name(entry->d_name))
+ if (guess_audio_format(entry->d_name) < 0)
continue;
if (f(dirname, entry->d_name) < 0)
goto out;
int header_sent;
};
-static void dccp_pre_select(__a_unused struct audio_format_handler *af,
- int *max_fileno, fd_set *rfds, __a_unused fd_set *wfds)
+static void dccp_pre_select( int *max_fileno, fd_set *rfds,
+ __a_unused fd_set *wfds)
{
if (listen_fd < 0)
return;
*max_fileno = PARA_MAX(*max_fileno, listen_fd);
}
-static void dccp_post_select(__a_unused struct audio_format_handler *af,
- fd_set *rfds, __a_unused fd_set *wfds)
+static void dccp_post_select(fd_set *rfds, __a_unused fd_set *wfds)
{
struct dccp_client *dc;
int ret;
return -E_DCCP_WRITE;
}
-static void dccp_send(__a_unused struct audio_format_handler *af,
- long unsigned current_chunk,
+static void dccp_send(long unsigned current_chunk,
__a_unused long unsigned chunks_sent, const char *buf, size_t len)
{
struct dccp_client *dc, *tmp;
}
if (!ret)
continue;
- if (!dc->header_sent && af->get_header_info && current_chunk) {
- header_buf = af->get_header_info(&header_len);
+ if (!dc->header_sent && current_chunk) {
+ header_buf = afs_get_header(&header_len);
if (!header_buf || header_len <= 0)
continue; /* header not yet available */
ret = dccp_write(dc->fd, header_buf, header_len);
return 1;
}
-static void http_send(__a_unused struct audio_format_handler *af,
- long unsigned current_chunk,
- __a_unused long unsigned chunks_sent, const char *buf, size_t len)
+static void http_send( long unsigned current_chunk,
+ __a_unused long unsigned chunks_sent, const char *buf, size_t len)
{
struct http_client *hc, *tmp;
int ret;
hc->status != HTTP_READY_TO_STREAM)
continue;
if (hc->status == HTTP_READY_TO_STREAM) {
- if (af->get_header_info && current_chunk) {
+ int hlen;
+ char *buf = afs_get_header(&hlen);
+ if (buf && hlen > 0 && current_chunk) {
/* need to send header */
- int hlen;
- char *buf = af->get_header_info(&hlen);
- if (!buf || hlen <= 0)
- continue; /* header not yet available */
PARA_INFO_LOG("queueing header: %d\n", hlen);
if (queue_packet(hc, buf, hlen) < 0)
continue;
return 0;
}
-static void http_post_select(__a_unused struct audio_format_handler *af, fd_set *rfds,
- fd_set *wfds)
+static void http_post_select(fd_set *rfds, fd_set *wfds)
{
int i = -1, match;
struct http_client *hc, *tmp;
free(hc);
}
-static void http_pre_select(struct audio_format_handler *af, int *max_fileno,
- fd_set *rfds, fd_set *wfds)
+static void http_pre_select(int *max_fileno, fd_set *rfds, fd_set *wfds)
{
struct http_client *hc, *tmp;
hc->check_w = 1;
break;
case HTTP_SENT_OK_MSG:
- if (!af || !afs_playing())
+ if (!afs_playing())
break; /* wait until server starts playing */
para_fd_set(hc->fd, wfds, max_fileno);
hc->check_w = 1;
}
}
-static int need_extra_header(struct audio_format_handler *af,
- long unsigned chunks_sent)
+static int need_extra_header(long unsigned current_chunk)
{
- /* FIXME: No need to compute this on every run */
- int mod = conf.ortp_header_interval_arg / (tv2ms(&af->chunk_tv) + 1);
- if (mod && (chunks_sent % mod))
+ static struct timeval last_header;
+ struct timeval now, diff;
+
+ if (!current_chunk)
+ return 0;
+ gettimeofday(&now, NULL);
+ tv_diff(&now, &last_header, &diff);
+ if (tv2ms(&diff) < conf.ortp_header_interval_arg)
return 0;
+ last_header = now;
return 1;
}
-static void ortp_send(struct audio_format_handler *af, long unsigned current_chunk,
- long unsigned chunks_sent, const char *buf, size_t len)
+static void ortp_send(long unsigned current_chunk, long unsigned chunks_sent,
+ const char *buf, size_t len)
{
struct ortp_target *ot, *tmp;
size_t sendbuf_len;
int header_len = 0;
- int packet_type = ORTP_DATA, stream_type = af && af->get_header_info; /* header stream? */
+ int packet_type = ORTP_DATA;
char *sendbuf, *header_buf = NULL;
+ struct timeval *chunk_tv;
if (self->status != SENDER_ON)
return;
+ chunk_tv = afs_chunk_time();
+ if (!chunk_tv)
+ return;
list_for_each_entry_safe(ot, tmp, &targets, node) {
if (!ot->session) {
ortp_init_session(ot);
}
if (!ot->chunk_ts)
ot->chunk_ts = rtp_session_time_to_ts(ot->session,
- tv2ms(&af->chunk_tv));
+ tv2ms(chunk_tv));
// PARA_DEBUG_LOG("len: %d, ts: %lu, ts: %d\n",
// len, ot->chunk_ts * chunks_sent, ot->chunk_ts);
ot->streaming = 1;
}
if (list_empty(&targets))
return;
- if (stream_type) {
- header_buf = af->get_header_info(&header_len);
- if (!need_extra_header(af, chunks_sent))
- header_len = 0;
- }
+ header_buf = afs_get_header(&header_len);
+ if (!need_extra_header(current_chunk))
+ header_len = 0;
sendbuf_len = ORTP_AUDIO_HEADER_LEN + header_len + len;
sendbuf = para_malloc(sendbuf_len);
if (!current_chunk)
else if (header_len)
packet_type = ORTP_HEADER;
WRITE_PACKET_TYPE(sendbuf, packet_type);
- WRITE_CHUNK_TIME(sendbuf, af->chunk_tv.tv_usec);
- WRITE_STREAM_TYPE(sendbuf, stream_type);
+ WRITE_CHUNK_TIME(sendbuf, chunk_tv->tv_usec);
+ WRITE_STREAM_TYPE(sendbuf, header_buf? 1 : 0);
WRITE_HEADER_LEN(sendbuf, header_len);
if (header_len)
memcpy(sendbuf + ORTP_AUDIO_HEADER_LEN, header_buf,
}
}
-static void ortp_pre_select(__a_unused struct audio_format_handler *af,
- __a_unused int *max_fileno, __a_unused fd_set *rfds,
+static void ortp_pre_select(__a_unused int *max_fileno, __a_unused fd_set *rfds,
__a_unused fd_set *wfds)
{
return;
* command. Of course, \a buf is a pointer to the chunk of data which
* should be sent, and \a len is the length of this buffer.
*/
- void (*send)(struct audio_format_handler *af, long unsigned current_chunk,
- long unsigned chunks_sent, const char *buf, size_t len);
+ void (*send)(long unsigned current_chunk, long unsigned chunks_sent,
+ const char *buf, size_t len);
/** add file descriptors to fd_sets
*
* The pre_select function of each supported sender is called just before
*
* \sa select(2)
*/
- void (*pre_select)(struct audio_format_handler *af, int *max_fileno, fd_set *rfds,
- fd_set *wfds);
+ void (*pre_select)(int *max_fileno, fd_set *rfds, fd_set *wfds);
/**
* handle the file descriptors which are ready for I/O
*
* set, this is the hook to check the result and do any I/O on those descriptors
* which are ready for reading/writing.
*/
- void (*post_select)(struct audio_format_handler *af, fd_set *rfds, fd_set *wfds);
+ void (*post_select)(fd_set *rfds, fd_set *wfds);
/**
* terminate all connected clients
*
continue;
if (!senders[i].pre_select)
continue;
- senders[i].pre_select(mmd->audio_format >= 0?
- &afl[mmd->audio_format] : NULL,
- &max_fileno,
- &rfds, &wfds);
+ senders[i].pre_select( &max_fileno, &rfds, &wfds);
}
if (selectors[mmd->selector_num].pre_select) {
ret = selectors[mmd->selector_num].pre_select(&rfds, &wfds);
continue;
if (!senders[i].post_select)
continue;
- senders[i].post_select(mmd->audio_format >= 0?
- &afl[mmd->audio_format] : NULL,
- &rfds, &wfds);
+ senders[i].post_select(&rfds, &wfds);
}
afs_send_chunk();
status_refresh();