libvorbis, libvorbisfile: http://www.xiph.org/downloads/.
The corresponding Debian packages are called libogg-dev
libvorbis-dev, other distributors chose similar names.
- The source of these is also available at
- *aac*:
For aac files (m4a) you'll need libfaad. Get it at
- gengetopt: ftp://ftp.gnu.org/pub/gnu/gengetopt/
- autoconf: ftp://ftp.gnu.org/pub/gnu/autoconf/
+ - git
- grutatxt
- help2man
- doxygen
int ret, shmid;
char buf[8];
long score;
-
+again:
PARA_NOTICE_LOG("getting next audio file\n");
ret = score_get_best(&aft_row, &score);
- if (ret < 0)
- return ret;
- ret = open_and_update_audio_file(aft_row, &afd, score);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+ goto no_admissible_files;
+ }
+ ret = open_and_update_audio_file(aft_row, score, &afd);
+ if (ret < 0) {
+ PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+ ret = score_delete(aft_row);
+ if (ret < 0) {
+ PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+ goto no_admissible_files;
+ }
+ goto again;
+ }
shmid = ret;
if (!write_ok(server_socket)) {
- PARA_EMERG_LOG("afs_socket not writable\n");
+ ret = -E_AFS_SOCKET;
goto destroy;
}
*(uint32_t *)buf = NEXT_AUDIO_FILE;
close(afd.fd);
if (ret >= 0)
return ret;
- PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
destroy:
shm_destroy(shmid);
return ret;
+no_admissible_files:
+ *(uint32_t *)buf = NO_ADMISSIBLE_FILES;
+ *(uint32_t *)(buf + 4) = (uint32_t)0;
+ return send_bin_buffer(server_socket, buf, 8);
}
/* Never fails if arg == NULL */
PARA_DEBUG_LOG("received: %s\n", buf);
if (!strcmp(buf, "new")) {
ret = open_next_audio_file();
- if (ret < 0)
- PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+ if (ret < 0) {
+ PARA_EMERG_LOG("%s\n", PARA_STRERROR(-ret));
+ unregister_tasks();
+ }
return;
}
PARA_ERROR_LOG("unknown command\n");
enum afs_server_code {
NEXT_AUDIO_FILE,
+ NO_ADMISSIBLE_FILES,
AFD_CHANGE
};
/* aft */
void aft_init(struct afs_table *t);
int aft_get_row_of_path(const char *path, struct osl_row **row);
-int open_and_update_audio_file(struct osl_row *aft_row,
- struct audio_file_data *afd, long score);
+int open_and_update_audio_file(struct osl_row *aft_row, long score,
+ struct audio_file_data *afd);
int load_afd(int shmid, struct audio_file_data *afd);
int load_afsi(struct afs_info *afsi, struct osl_object *obj);
void save_afsi(struct afs_info *afsi, struct osl_object *obj);
* Mmap the given audio file and update statistics.
*
* \param aft_row Determines the audio file to be opened and updated.
+ * \param score The score of the audio file.
* \param afd Result pointer.
*
* On success, the numplayed field of the audio file selector info is increased
*
* \return Positive shmid on success, negative on errors.
*/
-int open_and_update_audio_file(struct osl_row *aft_row,
- struct audio_file_data *afd, long score)
+int open_and_update_audio_file(struct osl_row *aft_row, long score,
+ struct audio_file_data *afd)
{
HASH_TYPE *aft_hash, file_hash[HASH_SIZE];
struct osl_object afsi_obj;
char *ret;
if (!(flags & LS_FLAG_FULL_PATH))
- return make_message("%s: %s\n%s:\n",
- status_item_list[SI_BASENAME], path,
- status_item_list[SI_DIRECTORY]);
+ return make_message("%s: %s\n",
+ status_item_list[SI_BASENAME], path);
basename = para_basename(path),
dirname = para_dirname(path);
ret = make_message("%s: %s\n%s: %s\n%s: %s\n",
lyrics_lines = make_lyrics_lines(afsi);
image_lines = make_image_lines(afsi);
filename_lines = make_filename_lines(d->path, opts->flags);
- if (opts->mode == LS_MODE_VERBOSE) {
- para_printf(b,
- "%s" /* filename stuff */
- "%s%s%s%s" /* score */
- "%s\n" /* attributes */
- "%s: %s\n" /* hash */
- "%s" /* image id, image name */
- "%s" /* lyrics */
- "%s: %dkbit/s\n" /* bitrate */
- "%s: %s\n" /* format */
- "%s: %dHz\n" /* frequency */
- "%s: %d\n" /* channels */
- "%s: %s\n" /* duration */
- "%s: %lu\n" /* seconds total */
- "%s: %d\n" /* num_played */
- "%s: %s\n" /* last_played */
- "%s", /* tag info */
- filename_lines,
- have_score? status_item_list[SI_SCORE] : "",
- have_score? ": " : "",
- score_buf,
- have_score? "\n" : "",
- att_lines,
- status_item_list[SI_HASH], asc_hash,
- image_lines,
- lyrics_lines,
- status_item_list[SI_BITRATE], afhi->bitrate,
- status_item_list[SI_FORMAT], audio_format_name(afsi->audio_format_id),
- status_item_list[SI_FREQUENCY], afhi->frequency,
- status_item_list[SI_CHANNELS], afhi->channels,
- status_item_list[SI_DURATION], duration_buf,
- status_item_list[SI_SECONDS_TOTAL], afhi->seconds_total,
- status_item_list[SI_NUM_PLAYED], afsi->num_played,
- status_item_list[SI_LAST_PLAYED], last_played_time,
- afhi->info_string
- );
- } else { /* mbox mode */ /* FIXME: merge with verbose output */
- struct osl_object lyrics_def;
- lyr_get_def_by_id(afsi->lyrics_id, &lyrics_def);
+ if (opts->mode == LS_MODE_MBOX)
para_printf(b,
"From foo@localhost %s\n"
"Received: from\nTo: bar\nFrom: a\n"
- "Subject: %s\n\n" /* path */
- "%s%s%s" /* score */
- "%s\n" /* attributes */
- "hash: %s\n"
- "%s\n" /* image id, image name */
- "lyrics_id: %s\n"
- "bitrate: %dkbit/s\n"
- "format: %s\n"
- "frequency: %dHz\n"
- "channels: %d\n"
- "duration: %s\n"
- "num_played: %d\n"
- "%s\n" /* tag info */
- "%s%s\n",
+ "Subject: %s\n\n",
last_played_time,
- d->path,
- have_score? "score: " : "", score_buf,
- have_score? "\n" : "",
- att_lines,
- asc_hash,
- image_lines,
- lyrics_lines,
- afhi->bitrate,
- audio_format_name(afsi->audio_format_id),
- afhi->frequency,
- afhi->channels,
- duration_buf,
- afsi->num_played,
- afhi->info_string,
- lyrics_def.data? "Lyrics:\n~~~~~~~\n" : "",
- lyrics_def.data? (char *)lyrics_def.data : ""
- );
- if (lyrics_def.data)
- osl_close_disk_object(lyrics_def.data);
+ d->path);
+ para_printf(b,
+ "%s" /* filename stuff */
+ "%s%s%s%s" /* score */
+ "%s\n" /* attributes */
+ "%s: %s\n" /* hash */
+ "%s" /* image id, image name */
+ "%s" /* lyrics */
+ "%s: %dkbit/s\n" /* bitrate */
+ "%s: %s\n" /* format */
+ "%s: %dHz\n" /* frequency */
+ "%s: %d\n" /* channels */
+ "%s: %s\n" /* duration */
+ "%s: %lu\n" /* seconds total */
+ "%s: %s\n" /* last played time */
+ "%s: %d\n" /* num_played */
+ "%s\n", /* tag info */
+ filename_lines,
+ have_score? status_item_list[SI_SCORE] : "",
+ have_score? ": " : "",
+ score_buf,
+ have_score? "\n" : "",
+ att_lines,
+ status_item_list[SI_HASH], asc_hash,
+ image_lines,
+ lyrics_lines,
+ status_item_list[SI_BITRATE], afhi->bitrate,
+ status_item_list[SI_FORMAT], audio_format_name(afsi->audio_format_id),
+ status_item_list[SI_FREQUENCY], afhi->frequency,
+ status_item_list[SI_CHANNELS], afhi->channels,
+ status_item_list[SI_DURATION], duration_buf,
+ status_item_list[SI_SECONDS_TOTAL], afhi->seconds_total,
+ status_item_list[SI_LAST_PLAYED], last_played_time,
+ status_item_list[SI_NUM_PLAYED], afsi->num_played,
+ afhi->info_string
+ );
+ if (opts->mode == LS_MODE_MBOX) {
+ struct osl_object lyrics_def;
+ lyr_get_def_by_id(afsi->lyrics_id, &lyrics_def);
+ if (lyrics_def.data) {
+ para_printf(b, "Lyrics:\n~~~~~~~\n%s",
+ (char *)lyrics_def.data);
+ osl_close_disk_object(&lyrics_def);
+ }
}
free(att_lines);
free(lyrics_lines);
if (argc != 1)
return -E_COMMAND_SYNTAX;
mmd_lock();
- if (!vss_paused())
+ if (!vss_paused() && !vss_stopped()) {
mmd->events++;
- mmd->new_vss_status_flags &= ~VSS_PLAYING;
- mmd->new_vss_status_flags &= ~VSS_NEXT;
+ mmd->new_vss_status_flags &= ~VSS_PLAYING;
+ mmd->new_vss_status_flags &= ~VSS_NEXT;
+ }
mmd_unlock();
return 1;
}
PARA_ERROR(INPUT_TOO_LARGE, "input too large for stdin command"), \
PARA_ERROR(AFS_SYNTAX, "afs syntax error"), \
PARA_ERROR(AFS_SIGNAL, "afs caught deadly signal"), \
+ PARA_ERROR(AFS_SOCKET, "afs socket not writable"), \
PARA_ERROR(AFS_PARENT_DIED, "fatal: server process terminated"), \
PARA_ERROR(AUDIO_FORMAT, "audio format not recognized"), \
PARA_ERROR(CHUNK, "unable to get chunk"), \
PARA_ERROR(SHORT_AFS_READ, "short read from afs socket"), \
- PARA_ERROR(BAD_AFS_CODE, "received junk from afs"), \
+ PARA_ERROR(NOFD, "did not receive open fd from afs"), \
#define CRYPT_ERRORS \
close(mixer_fd);
}
-static int client_cmd(const char *cmd,...)
+static void client_cmd(const char *cmd)
{
int ret, fds[3] = {0, 0, 0};
pid_t pid;
PARA_INFO_LOG("%s\n", cmdline);
ret = para_exec_cmdline_pid(&pid, cmdline, fds);
free(cmdline);
- return ret;
+ if (ret < 0)
+ exit(EXIT_FAILURE);
+ do
+ ret = wait(NULL);
+ while (ret != -1 && errno != ECHILD);
}
static void change_afs_mode_and_play(char *afs_mode)
mark_mapped_object_invalid(t, r->num, i);
continue;
}
- if (st == OSL_NO_STORAGE)
+ if (st == OSL_NO_STORAGE && !(cd->storage_flags & OSL_DONT_FREE))
free(r->volatile_objects[col->volatile_num].data);
}
if (t->num_mapped_columns) {
{
struct osl_column *col;
struct rb_node *node;
- int ret = check_rbtree_col(t, col_num, &col);
+ unsigned num_rows;
+ int ret;
+ if (n == 0)
+ return -E_RB_KEY_NOT_FOUND;
+ ret = osl_get_num_rows(t, &num_rows);
+ if (ret < 0)
+ return ret;
+ if (n > num_rows)
+ return -E_RB_KEY_NOT_FOUND;
+ ret = check_rbtree_col(t, col_num, &col);
if (ret < 0)
return ret;
node = rb_nth(col->rbtree.rb_node, n);
*/
/**
- * \file stat.c functions used for sending/receiving the status of para_server
- * and para_audiod
+ * \file stat.c Functions used for sending/receiving the status of para_server
+ * and para_audiod.
*/
#include "string.h"
#include "fd.h"
-/** the maximal number of simultaneous connections */
+/** The maximal number of simultaneous connections. */
#define MAX_STAT_CLIENTS 50
/**
- * describes a status client of para_audiod
+ * Describes a status client of para_audiod.
*
* There's one such structure per audiod client that sent the 'stat' command.
*
* keeps a list of connected status clients.
*/
struct stat_client {
- /** the stat client's file descriptor */
+ /** The stat client's file descriptor. */
int fd;
- /** bitmask of those status items the client is interested in */
+ /** Bitmask of those status items the client is interested in. */
long unsigned item_mask;
- /** its entry in the list of stat clients */
+ /** Its entry in the list of stat clients. */
struct list_head node;
};
PARA_INFO_LOG("stat client on fd %d\n", sc->fd);
}
/**
- * add a status client to the list
+ * Add a status client to the list.
*
- * \param fd the file descriptor of the client
- * \param mask bitfield of status items for this client
+ * \param fd The file descriptor of the client.
+ * \param mask Bitfield of status items for this client.
*
* Only those status items having the bit set in \a mask will be
* sent to the client.
return 1;
}
/**
- * write a message to all connected status clients
+ * Write a message to all connected status clients.
*
- * \param msg a \p NULL terminated buffer
- * \param itemnum The number of the status item of \a msg
+ * \param msg A \p NULL terminated buffer.
+ * \param itemnum The number of the status item of \a msg.
*
* On write errors, remove the status client from the client list and close its
* file descriptor.
continue;
FD_ZERO(&wfds);
FD_SET(fd, &wfds);
-// PARA_DEBUG_LOG("%s: p=%lx\n", __func__, (long)p);
ret = para_select(fd + 1, NULL, &wfds, &tv);
if (ret > 0) {
ret = write(fd, msg, len);
PARA_DEBUG_LOG("dumped %s to fd %d, ret = %d\n", msg, fd, ret);
- if (ret == len )
+ if (ret == len)
continue;
}
/* write error or fd not ready for writing */
}
/**
- * check if string is a known status item.
+ * Check if string is a known status item.
*
- * \param item buffer containing the text to check
+ * \param item Buffer containing the text to check.
*
* \return If \a item is a valid status item, the number of that status item is
* returned. Otherwise, this function returns \p -E_UNKNOWN_STAT_ITEM.
}
/**
- * check if line starts with known status item.
+ * Check if line starts with known status item.
*
- * \param line buffer containing the line
+ * \param line Buffer containing the line.
*
* \return If the beginning of \a line matches any paraslash status item and is
* followed by a colon, the number of that status item is returned. Otherwise,
&& !(mmd->new_vss_status_flags & VSS_PLAYING);
}
+/**
+ * Check if the vss is currently stopped.
+ *
+ * \return Greater than zero if paused, zero otherwise.
+ *
+ */
+unsigned int vss_stopped(void)
+{
+ return (mmd->new_vss_status_flags & VSS_NEXT)
+ && !(mmd->new_vss_status_flags & VSS_PLAYING);
+}
+
/**
* Initialize the virtual streaming system.
*
struct iovec iov;
int ret = 0;
+ *fd = -1;
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
msg.msg_iov = &iov;
ret = recvmsg(afs_socket, &msg, 0);
if (ret < 0)
return -ERRNO_TO_PARA_ERROR(errno);
+ afsss = AFS_SOCKET_READY;
if (iov.iov_len != sizeof(buf))
return -E_SHORT_AFS_READ;
*code = *(uint32_t*)buf;
static void recv_afs_result(void)
{
- int ret, passed_fd = -1, shmid;
+ int ret, passed_fd, shmid;
uint32_t afs_code = 0, afs_data = 0;
struct stat statbuf;
struct timeval now;
ret = recv_afs_msg(&passed_fd, &afs_code, &afs_data);
if (ret < 0)
goto err;
- PARA_DEBUG_LOG("got the fd: %d, code: %u, shmid: %u\n",
- passed_fd, afs_code, afs_data);
- ret = -E_BAD_AFS_CODE;
+ PARA_DEBUG_LOG("fd: %d, code: %u, shmid: %u\n", passed_fd, afs_code,
+ afs_data);
+ ret = -E_NOFD;
if (afs_code != NEXT_AUDIO_FILE)
goto err;
- afsss = AFS_SOCKET_READY;
+ if (passed_fd < 0)
+ goto err;
shmid = afs_data;
ret = load_afd(shmid, &mmd->afd);
if (ret < 0)
if (passed_fd >= 0)
close(passed_fd);
PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+ mmd->new_vss_status_flags = VSS_NEXT;
}
void vss_post_select(fd_set *rfds, fd_set *wfds)
unsigned int vss_next(void);
unsigned int vss_repos(void);
unsigned int vss_paused(void);
+unsigned int vss_stopped(void);
char *vss_get_header(size_t *header_len);
struct timeval *vss_chunk_time(void);
const char *supported_audio_formats(void);