# defined locally in source files will be included in the documentation.
# If set to NO only classes defined in header files are included.
-EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_CLASSES = NO
# This flag is only useful for Objective-C code. When set to YES local
# methods, which are defined in the implementation section but not in
HAVE_FAAD \
HAVE_OGGVORBIS \
__GNUC__=4 \
- __GNUC_MINOR__=4
+ __GNUC_MINOR__=4 \
+ HAVE_UCRED
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
@[ -z "$(Q)" ] || echo 'CC $<'
$(Q) $(CC) -c -o $@ $(CPPFLAGS) $(DEBUG_CPPFLAGS) $<
-# We depend on the *.cmdline.[ch] files as these must be present for depend.sh
-# to work. The first dependency is explititly given as it is used by $<.
-
-$(object_dir)/%.cmdline.d: %.cmdline.c $(cmdline_generated) | $(object_dir)
+$(object_dir)/%.cmdline.d: $(cmdline_dir)/%.cmdline.c | $(object_dir)
@[ -z "$(Q)" ] || echo 'DEP $<'
- $(Q) ./depend.sh $(object_dir) $(CPPFLAGS) $< > $@
+ $(Q) ./depend.sh $(object_dir) $(cmdline_dir) $(CPPFLAGS) $< > $@
-$(object_dir)/%.d: %.c $(cmdline_generated) | $(object_dir)
+$(object_dir)/%.d: %.c | $(object_dir)
@[ -z "$(Q)" ] || echo 'DEP $<'
- $(Q) ./depend.sh $(object_dir) $(CPPFLAGS) $< > $@
+ $(Q) ./depend.sh $(object_dir) $(cmdline_dir) $(CPPFLAGS) $< > $@
recv_objs := $(addprefix $(object_dir)/, @recv_objs@)
filter_objs := $(addprefix $(object_dir)/, @filter_objs@)
afh_objs := $(addprefix $(object_dir)/, @afh_objs@)
all_objs := $(recv_objs) $(filter_objs) $(client_objs) $(gui_objs) \
- $(audiod_objs ) $(audioc_objs) $(fade_objs) $(server_objs) \
+ $(audiod_objs) $(audioc_objs) $(fade_objs) $(server_objs) \
$(write_objs) $(afh_objs)
+
+ifeq ($(findstring clean, $(MAKECMDGOALS)),)
-include $(all_objs:.o=.d)
+endif
para_recv: $(recv_objs)
@[ -z "$(Q)" ] || echo 'LD $@'
0.4.1 (to be announced) "concurrent horizon"
--------------------------------------------
-Support for another audio format and bug fixes: All fixes that have
-been accumulated in the 0.3.6 release appear in this release as well.
-
- - wma support
- - new afh option: --human to activate human-readable output
+Support for another audio format, minor feature enhancements and lots of bug
+fixes. All fixes that have been accumulated in the maint branch (in particular
+those mentionened in the 0.3.6 release notes) appear in this release as well.
+
+ - wma support.
+ - new afh option: --human to activate human-readable output.
+ - new server/audiod option: --log-timing to print timing information.
+ - build system improvements.
+ - source code documentation updates.
-------------------------------------
0.3.6 (2009-12-07) "cubic continuity"
void *data);
};
-enum play_mode {PLAY_MODE_MOOD, PLAY_MODE_PLAYLIST};
+/** How audio files are selected by afs. */
+enum play_mode {
+ /** Admissible files are determined by a mood definition. */
+ PLAY_MODE_MOOD,
+ /** All listed files are admissible. */
+ PLAY_MODE_PLAYLIST,
+};
/**
* Data about one audio file.
struct afh_info afhi;
};
+/**
+ * Codes used for communication between the server and the afs process.
+ *
+ * Before forking the afs child, para_server creates a bidirectional pipe
+ * through which both processes communicate. Usually para_server requests a new
+ * audio in order to start streaming or when the end of the current audio file
+ * has been reached. The afs process responds to such a request by sending
+ * back an eight byte buffer. The first four bytes is the uint32_t
+ * representation of the code, usually \p NEXT_AUDIO_FILE if an admissible
+ * audio file was found, successfully opened and verified. The other four bytes
+ * represent the shared memory id of the shared memory area that contains
+ * details about the audio file to be streamed next. The open file descriptor
+ * of that file is also passed from afs to para_server through the same pipe.
+ */
enum afs_server_code {
+ /** An audio file was successfully opened. */
NEXT_AUDIO_FILE,
+ /** No admissible audio file was found. */
NO_ADMISSIBLE_FILES,
- AFD_CHANGE
};
/** Flags passed to for_each_matching_row(). */
return ret;
}
+/**
+ * Extract a afd stored in a shared memory area.
+ *
+ * Attach the shared memory area given by \a shmid, load the audio file data
+ * stored therein and detach the area afterwards. Called by vss, after
+ * receiving a positive response to the request for the next audio file.
+ +
+ * \param shmid The identifier of the shared memory area containing the afd.
+ * \param afd Result pointer.
+ *
+ * \return Standard.
+ */
int load_afd(int shmid, struct audio_file_data *afd)
{
void *shm_afd;
}
}
+/**
+ * Initialize the audio file table.
+ *
+ * \param t Pointer to the structure to be initialized.
+ */
void aft_init(struct afs_table *t)
{
t->open = aft_open;
a->receiver->close(s->receiver_node);
free(s->receiver_node);
s->receiver_node = NULL;
+ stat_task->current_audio_format_num = -1;
}
static void kill_all_decoders(int error)
stat_task->length_seconds = 0;
stat_task->offset_seconds = 0;
stat_task->vss_status = 0;
+ stat_task->current_audio_format_num = -1;
audiod_status_dump();
}
daemon_set_flag(DF_LOG_TIME);
daemon_set_flag(DF_LOG_HOSTNAME);
daemon_set_flag(DF_LOG_LL);
+ if (conf.log_timing_given)
+ daemon_set_flag(DF_LOG_TIMING);
if (conf.logfile_given) {
daemon_set_logfile(conf.logfile_arg);
daemon_open_log_or_die();
fi
aclocal -I . &> /dev/null
autoconf
-autoheader
+autoheader
echo configuring...
./configure $@ > /dev/null
echo compiling...
-make clean all > /dev/null
+make clean2 &> /dev/null
+make > /dev/null
#define VLC_TYPE int16_t
+/** A variable length code table. */
struct vlc {
+ /** Number of bits of the table. */
int bits;
- VLC_TYPE(*table)[2]; ///< code, bits
- int table_size, table_allocated;
+ /** The code and the bits table. */
+ VLC_TYPE(*table)[2];
+ /** The size of the table. */
+ int table_size;
+ /** Amount of memory allocated so far. */
+ int table_allocated;
};
static inline uint32_t show_bits(struct getbit_context *gbc, int num)
* Licensed under the GPL v2. For licencing details see COPYING.
*/
-/** \file client.h common client functions and exported symbols from client_common.c */
+/** \file client.h Common client functions and exported symbols from client_common.c. */
#include <openssl/rc4.h>
-/**
- * the different states of a connection from the view of the client
- */
+/** The different states of a connection from the view of the client. */
enum {
- /** tcp connection is established */
+ /** TCP connection is established. */
CL_CONNECTED,
- /** server sends the welcome message */
+ /** Server sends the welcome message. */
CL_RECEIVED_WELCOME,
- /** client sends the authentification request */
+ /** Client sends the authentification request. */
CL_SENT_AUTH,
- /** server sends a challenge */
+ /** Server sends a challenge. */
CL_RECEIVED_CHALLENGE,
- /** clientd solves the challenge and sends the result */
+ /** Client solves the challenge and sends the result. */
CL_SENT_CH_RESPONSE,
- /** server accepts this authentication */
+ /** Server accepts this authentication. */
CL_RECEIVED_PROCEED,
- /** client sends the command */
+ /** Client sends the command. */
CL_SENT_COMMAND,
- /** server expects data */
+ /** Server expects data. */
CL_SENDING,
- /** client expects data */
+ /** Client expects data. */
CL_RECEIVING,
};
-/** size of the receiving buffer */
+/** The size of the receiving buffer. */
#define CLIENT_BUFSIZE 8192
-/**
- * data specific to a client task
- */
+/** Data specific to a client task. */
struct client_task {
- /** the state of the connection */
+ /** The state of the connection. */
int status;
/** The file descriptor and the rc4 keys. */
struct rc4_context rc4c;
- /** the configuration (including the command) */
+ /** The configuration (including the command). */
struct client_args_info conf;
- /** the config file for client options */
+ /** The config file for client options. */
char *config_file;
- /** the RSA private key */
+ /** The RSA private key. */
char *key_file;
- /** paraslash user name */
+ /** Paraslash user name. */
char *user;
- /** the client task structure */
+ /** The client task structure. */
struct task task;
- /** the buffer used for handshake and receiving */
+ /** The buffer used for handshake and receiving. */
char *buf;
- /** number of bytes loaded in \p buf */
+ /** Number of bytes loaded in \a buf. */
size_t loaded;
- /** non-zero if the pre_select hook added \p fd to the read fd set */
+ /** Non-zero if the pre_select hook added \a fd to the read fd set. */
int check_r;
- /** non-zero if the pre_select hook added \p fd to the write fd set */
+ /** Non-zero if the pre_select hook added \a fd to the write fd set. */
int check_w;
- /** pointer to the data to be sent to para_server */
+ /** Pointer to the data to be sent to para_server. */
char *inbuf;
- /** number of bytes loaded in \p inbuf */
+ /** Number of bytes loaded in \a inbuf. */
size_t *in_loaded;
/** Non-zero if input task encountered an eof or an error condition. */
int *in_error;
#include <pwd.h>
#include <sys/types.h> /* getgrnam() */
#include <grp.h>
+#include <sys/time.h>
+#include <stdbool.h>
#include "para.h"
#include "daemon.h"
me->flags &= ~flag;
}
-static unsigned daemon_test_flag(unsigned flag)
+static bool daemon_test_flag(unsigned flag)
{
return me->flags & flag;
}
va_list argp;
FILE *fp;
struct tm *tm;
- time_t t1;
char *color;
+ bool log_time = daemon_test_flag(DF_LOG_TIME), log_timing =
+ daemon_test_flag(DF_LOG_TIMING);
ll = PARA_MIN(ll, NUM_LOGLEVELS - 1);
ll = PARA_MAX(ll, LL_DEBUG);
color = daemon_test_flag(DF_COLOR_LOG)? me->log_colors[ll] : NULL;
if (color)
fprintf(fp, "%s", color);
- if (daemon_test_flag(DF_LOG_TIME)) { /* print date and time */
- char str[100];
- time(&t1);
- tm = localtime(&t1);
- strftime(str, sizeof(str), "%b %d %H:%M:%S", tm);
- fprintf(fp, "%s ", str);
+ if (log_time || log_timing) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ if (daemon_test_flag(DF_LOG_TIME)) { /* print date and time */
+ time_t t1 = tv.tv_sec;
+ char str[100];
+ tm = localtime(&t1);
+ strftime(str, sizeof(str), "%b %d %H:%M:%S", tm);
+ fprintf(fp, "%s%s", str, log_timing? ":" : " ");
+ }
+ if (log_timing) /* print milliseconds */
+ fprintf(fp, "%04lu ", (long unsigned)tv.tv_usec / 1000);
}
if (daemon_test_flag(DF_LOG_HOSTNAME)) {
if (!me->hostname)
DF_LOG_LL = 8,
/** Use colored output. */
DF_COLOR_LOG = 16,
+ /** Include milliseconds in log output. */
+ DF_LOG_TIMING = 32
};
#!/bin/sh
-dir="$1"
+
+# Call gcc to output a rule suitable for make describing the dependencies of
+# the given input file and parse the output to add a *.d target with the same
+# dependencies.
+
+# The first two arguments to that script are special: $1 is the object
+# directory. This string is prefixed to both the .o and the .d target. $2 is
+# the directory that contains the *.cmdline.h files generated by gengetopt.
+
+# As gcc outputs the dependencies on the *.cmdline.h files either as either
+# foo.cmdline.h or as $cmdline_dir/foo,cmdline.h, depending on whether the
+# latter file exists, we prefix the former with $2/
+
+object_dir="$1"
+cmdline_dir="$2"
shift
-gcc -MM -MG "$@" | sed -e "s@^\(.*\)\.o:@$dir/\1.d $dir/\1.o:@"
+shift
+
+LC_ALL=C gcc -MM -MG "$@" \
+ | sed -e "s@^\(.*\)\.o:@$object_dir/\1.d $object_dir/\1.o:@" \
+ -e "s@[ ^]\([a-zA-Z0-9_]\+\.cmdline.h\)@ $cmdline_dir/\1@g"
#include "string.h"
#include "fec.h"
-#define GF_BITS 8 /* code over GF(256) */
+/** Code over GF(256). */
+#define GF_BITS 8
+/** The largest number in GF(256) */
#define GF_SIZE ((1 << GF_BITS) - 1)
/*
* To speed up computations, we have tables for logarithm, exponent and inverse
- * of a number. We use a table for multiplication as well (it takes 64K, no big
- * deal even on a PDA, especially because it can be pre-initialized an put into
- * a ROM!). The macro gf_mul(x,y) takes care of multiplications.
+ * of a number.
+ */
+
+/** Index->poly form conversion table. */
+static unsigned char gf_exp[2 * GF_SIZE];
+
+/** Poly->index form conversion table. */
+static int gf_log[GF_SIZE + 1];
+
+/** Inverse of a field element. */
+static unsigned char inverse[GF_SIZE + 1];
+
+/**
+ * The multiplication table.
+ *
+ * We use a table for multiplication as well. It takes 64K, no big deal even on
+ * a PDA, especially because it can be pre-initialized and put into a ROM.
+ *
+ * \sa \ref gf_mul.
*/
-static unsigned char gf_exp[2 * GF_SIZE]; /* index->poly form conversion table */
-static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */
-static unsigned char inverse[GF_SIZE + 1]; /* inverse of field elem. */
static unsigned char gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];
-/* Multiply two numbers. */
+
+/** Multiply two GF numbers. */
#define gf_mul(x,y) gf_mul_table[x][y]
/* Compute x % GF_SIZE without a slow divide. */
inverse[i] = gf_exp[GF_SIZE - gf_log[i]];
}
+/** How often the loop is unrolled. */
+#define UNROLL 16
+
/*
* Compute dst[] = dst[] + c * src[]
*
* This is used often, so better optimize it! Currently the loop is unrolled 16
* times. The case c=0 is also optimized, whereas c=1 is not.
*/
-#define UNROLL 16
static void addmul(unsigned char *dst1, const unsigned char const *src1,
unsigned char c, int sz)
{
}
}
+/** Swap two numbers. */
#define FEC_SWAP(a,b) {typeof(a) tmp = a; a = b; b = tmp;}
/*
* OF SUCH DAMAGE.
*/
-#define FEC_MAGIC 0xFECC0DEC
+/** Each FEC slice contains a FEC header of this size. */
#define FEC_HEADER_SIZE 32
+/** The FEC header starts with this magic value. */
+#define FEC_MAGIC 0xFECC0DEC
struct fec_parms;
fg->idx[i] = -1;
}
free(fg->data);
+ fg->data = NULL;
free(fg->idx);
+ fg->idx = NULL;
fg->num_slices = 0;
memset(&fg->h, 0, sizeof(struct fec_header));
fg->num_received_slices = 0;
return 1;
}
+/**
+ * The different states of a complete FEC group.
+ *
+ * Even if a FEC group has been received successfully, it probably can not be
+ * used right away because some streams (ogg, wma) need to receive an audio
+ * file header before decoding can start.
+ */
enum fec_group_usability {
+ /** Drop the group (because we did not receive the header yet). */
FEC_GROUP_UNUSABLE,
+ /** Use all data in the group. */
FEC_GROUP_USABLE,
+ /** Use the group, but drop its audio file header. */
FEC_GROUP_USABLE_SKIP_HEADER,
+ /** Use the group, including its header. */
FEC_GROUP_USABLE_WITH_HEADER
};
include(color.m4)
include(config_file.m4)
include(logfile.m4)
+include(log_timing.m4)
include(daemon.m4)
include(user.m4)
include(group.m4)
--- /dev/null
+<qu>
+option "log-timing" T
+#~~~~~~~~~~~~~~~~~~~~
+"show milliseconds in log messages"
+flag off
+details = "
+ Selecting this option causes milliseconds to be included in
+ the log message output. This allows to measure the interval
+ between log messages in milliseconds which is useful for
+ identifying timing problems.
+"
+</qu>
$(ggo_dir)/loglevel.m4 $(ggo_dir)/color.m4 \
$(ggo_dir)/config_file.m4 $(ggo_dir)/logfile.m4 \
$(ggo_dir)/daemon.m4 $(ggo_dir)/user.m4 \
- $(ggo_dir)/group.m4
+ $(ggo_dir)/group.m4 $(ggo_dir)/log_timing.m4
$(ggo_dir)/afh.ggo: $(ggo_dir)/loglevel.m4
$(ggo_dir)/audioc.ggo: $(ggo_dir)/loglevel.m4
</qu>
include(loglevel.m4)
+include(log_timing.m4)
include(color.m4)
include(daemon.m4)
include(user.m4)
phsd->status = HTTP_CONNECTED;
}
-static void http_pre_select(int *max_fileno, fd_set *rfds, __a_unused fd_set *wfds)
+static void http_pre_select(int *max_fileno, fd_set *rfds, fd_set *wfds)
{
struct sender_client *sc, *tmp;
struct private_http_sender_data *phsd = sc->private_data;
if (phsd->status == HTTP_CONNECTED) /* need to recv get request */
para_fd_set(sc->fd, rfds, max_fileno);
+ if (phsd->status == HTTP_GOT_GET_REQUEST ||
+ phsd->status == HTTP_INVALID_GET_REQUEST)
+ para_fd_set(sc->fd, wfds, max_fileno);
}
}
ret = 1;
out:
if (ret < 0) {
- PARA_NOTICE_LOG("n = %d, did not receive pattern '%s'\n", n,
- pattern);
+ PARA_NOTICE_LOG("did not receive pattern '%s'\n", pattern);
if (n > 0)
- PARA_NOTICE_LOG("recvd: %s\n", buf);
+ PARA_NOTICE_LOG("recvd %d bytes: %s\n", n, buf);
+ else if (n < 0)
+ PARA_NOTICE_LOG("%s\n", para_strerror(-n));
}
free(buf);
return ret;
daemon_set_flag(DF_LOG_PID);
daemon_set_flag(DF_LOG_LL);
daemon_set_flag(DF_LOG_TIME);
+ if (conf.log_timing_given)
+ daemon_set_flag(DF_LOG_TIMING);
ret = 1;
out:
free(cf);
return msg;
}
+/**
+ * Free the content of a pointer and set it to \p NULL.
+ *
+ * This is equivalent to "free(*arg); *arg = NULL;".
+ *
+ * \param arg The pointer whose content should be freed.
+ */
void freep(void *arg)
{
void **ptr = (void **)arg;
private_data);
}
+/** Return the hex characters of the lower 4 bits. */
#define hex(a) (hexchar[(a) & 15])
+
static void write_size_header(char *buf, int n)
{
static char hexchar[] = "0123456789abcdef";
buf[4] = ' ';
}
+/**
+ * Read a four-byte hex-number and return its value.
+ *
+ * Each status item sent by para_server is prefixed with such a hex number in
+ * ASCII which describes the size of the status item.
+ *
+ * \param buf The buffer which must be at least four bytes long.
+ *
+ * \return The value of the hex number on success, \p -E_SIZE_PREFIX if the
+ * buffer did not contain only hex digits.
+ */
int read_size_header(const char *buf)
{
int i, len = 0;
return ret;
}
+/**
+ * Compile a regular expression.
+ *
+ * This simple wrapper calls regcomp() and logs a message on errors.
+ *
+ * \param preg See regcomp(3).
+ * \param regex See regcomp(3).
+ * \param cflags See regcomp(3).
+ *
+ * \return Standard.
+ */
int para_regcomp(regex_t *preg, const char *regex, int cflags)
{
char *buf;
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/**
- * \file wmadata.h Various WMA tables.
- */
+/** \file wmadata.h Various WMA tables. */
+/** Contains huffcodes, huffbits and run/level tables. */
struct coef_vlc_table {
/** Total number of codes. */
int n;
- /** Number of levels. */
- int max_level;
/** VLC bit values. */
const uint32_t *huffcodes;
/** VLC bit size. */
#define DEF_COEF_TABLE(_x) { \
.n = sizeof(coef ## _x ## _huffbits), \
- .max_level = sizeof(levels ## _x) / 2, \
.huffcodes = coef ## _x ## _huffcodes, \
.huffbits = coef ## _x ##_huffbits, \
.levels = levels ## _x}
#define LSP_POW_BITS 7
struct private_wmadec_data {
+ /** Information contained in the audio file header. */
struct asf_header_info ahi;
struct getbit_context gb;
/** Whether to use the bit reservoir. */
uint16_t exponent_bands[BLOCK_NB_SIZES][25];
/** The index of the first coef in high band. */
int high_band_start[BLOCK_NB_SIZES];
- int coefs_end[BLOCK_NB_SIZES]; ///< max number of coded coefficients
+ /** Maximal number of coded coefficients. */
+ int coefs_end[BLOCK_NB_SIZES];
int exponent_high_sizes[BLOCK_NB_SIZES];
int exponent_high_bands[BLOCK_NB_SIZES][HIGH_BAND_MAX_SIZE];
struct vlc hgain_vlc;
uint16_t *run_table[2];
uint16_t *level_table[2];
const struct coef_vlc_table *coef_vlcs[2];
- /* frame info */
- int frame_len; ///< frame length in samples
- int frame_len_bits; ///< frame_len = 1 << frame_len_bits
+ /** Frame length in samples. */
+ int frame_len;
+ /** log2 of frame_len. */
+ int frame_len_bits;
/** Number of block sizes. */
int nb_block_sizes;
/* block info */
int reset_block_lengths;
- int block_len_bits; ///< log2 of current block length
- int next_block_len_bits; ///< log2 of next block length
- int prev_block_len_bits; ///< log2 of prev block length
- int block_len; ///< block length in samples
- int block_pos; ///< current position in frame
- uint8_t ms_stereo; ///< true if mid/side stereo mode
- uint8_t channel_coded[MAX_CHANNELS]; ///< true if channel is coded
- int exponents_bsize[MAX_CHANNELS]; ///< log2 ratio frame/exp. length
+ /** log2 of current block length. */
+ int block_len_bits;
+ /** log2 of next block length. */
+ int next_block_len_bits;
+ /** log2 of previous block length. */
+ int prev_block_len_bits;
+ /** Block length in samples. */
+ int block_len;
+ /** Current position in frame. */
+ int block_pos;
+ /** True if mid/side stereo mode. */
+ uint8_t ms_stereo;
+ /** True if channel is coded. */
+ uint8_t channel_coded[MAX_CHANNELS];
+ /** log2 ratio frame/exp. length. */
+ int exponents_bsize[MAX_CHANNELS];
+
float exponents[MAX_CHANNELS][BLOCK_MAX_SIZE];
float max_exponent[MAX_CHANNELS];
int16_t coefs1[MAX_CHANNELS][BLOCK_MAX_SIZE];
float output[BLOCK_MAX_SIZE * 2];
struct mdct_context *mdct_ctx[BLOCK_NB_SIZES];
float *windows[BLOCK_NB_SIZES];
- /* output buffer for one frame and the last for IMDCT windowing */
+ /** Output buffer for one frame and the last for IMDCT windowing. */
float frame_out[MAX_CHANNELS][BLOCK_MAX_SIZE * 2];
- /* last frame info */
+ /** Last frame info. */
uint8_t last_superframe[MAX_CODED_SUPERFRAME_SIZE + 4]; /* padding added */
int last_bitoffset;
int last_superframe_len;