+++ /dev/null
-/*
- * Copyright (C) 2006 Andre Noll <maan@tuebingen.mpg.de>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
-
-/** \file osx_write.c paraslash's output plugin for MacOs */
-
-/*
- * based on mosx-mpg123, by Guillaume Outters and Steven A. Kortze
- * <skortze@sourceforge.net>
- */
-
-#include <regex.h>
-#include <sys/types.h>
-#include <lopsub.h>
-
-#include "write_cmd.lsg.h"
-#include "para.h"
-#include "fd.h"
-#include "string.h"
-#include "list.h"
-#include "sched.h"
-#include "buffer_tree.h"
-#include "write.h"
-#include "ipc.h"
-#include "error.h"
-
-#include <CoreServices/CoreServices.h>
-#include <AudioUnit/AudioUnit.h>
-#include <AudioToolbox/AudioToolbox.h>
-
-/** Data specific to the osx writer. */
-struct private_osx_write_data {
- /** The main CoreAudio handle. */
- AudioUnit audio_unit;
- /** True if we wrote some audio data. */
- bool playing;
- /** Sample rate of the current audio stream. */
- unsigned sample_rate;
- /** Sample format of the current audio stream */
- unsigned sample_format;
- /** Number of channels of the current audio stream. */
- unsigned channels;
- /**
- * Serializes access to buffer tree nodes between the writer and
- * the callback which runs in a different thread.
- */
- int mutex;
- /**
- * The btr node of the callback.
- *
- * Although access to the btr node is serialized between the writer and
- * the callback via the above mutex, this does not stop other buffer
- * tree nodes, for example the decoder, to race against the osx
- * callback.
- *
- * However, since all operations on buffer tree nodes are local in the
- * sense that they only affect one level in the buffer tree (i.e.
- * parent or child nodes, but not the grandparent or the
- * grandchildren), we may work around this problem by using another
- * buffer tree node for the callback.
- *
- * The writer grabs the mutex in its post_select method and pushes down
- * the buffers to the callback node.
- */
- struct btr_node *callback_btrn;
-};
-
-/* This function writes the address and the number of bytes to one end of the socket.
- * The post_select() function then fills the buffer and notifies the callback also
- * through the socket.
- */
-static OSStatus osx_callback(void *cb_arg, __a_unused AudioUnitRenderActionFlags *af,
- __a_unused const AudioTimeStamp *ts, __a_unused UInt32 bus_number,
- __a_unused UInt32 num_frames, AudioBufferList *abl)
-{
- int i;
- struct writer_node *wn = cb_arg;
- struct private_osx_write_data *powd;
- size_t samples_have, samples_want = 0;
-
- powd = wn->private_data;
- mutex_lock(powd->mutex);
- powd = wn->private_data;
- if (!powd || !wn->btrn)
- goto out;
- /*
- * We fill with zeros if no data was yet written and we do not have
- * enough to fill all buffers.
- */
- if (!powd->playing) {
- size_t want = 0, have =
- btr_get_input_queue_size(powd->callback_btrn);
- for (i = 0; i < abl->mNumberBuffers; i++)
- want += abl->mBuffers[i].mDataByteSize;
- if (have < want) {
- PARA_DEBUG_LOG("deferring playback (have = %zu < %zu = want)\n",
- have, want);
- for (i = 0; i < abl->mNumberBuffers; i++)
- memset(abl->mBuffers[i].mData, 0,
- abl->mBuffers[i].mDataByteSize);
- goto out;
- }
- powd->playing = true;
- }
-
- for (i = 0; i < abl->mNumberBuffers; i++) {
- /* what we have to fill */
- void *dest = abl->mBuffers[i].mData;
- size_t sz = abl->mBuffers[i].mDataByteSize, samples, bytes;
-
- samples_want = sz / wn->min_iqs;
- while (samples_want > 0) {
- char *buf;
- btr_merge(powd->callback_btrn, wn->min_iqs);
- samples_have = btr_next_buffer(powd->callback_btrn, &buf) / wn->min_iqs;
- //PARA_INFO_LOG("i: %d want %zu samples to addr %p, have: %zu\n", i, samples_want,
- // dest, samples_have);
- samples = PARA_MIN(samples_have, samples_want);
- if (samples == 0)
- break;
- bytes = samples * wn->min_iqs;
- memcpy(dest, buf, bytes);
- btr_consume(powd->callback_btrn, bytes);
- samples_want -= samples;
- dest += bytes;
- }
- if (samples_want == 0)
- continue;
- if (btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF) >= 0)
- PARA_INFO_LOG("zero-padding (%zu samples)\n",
- samples_want);
- memset(dest, 0, samples_want * wn->min_iqs);
- break;
- }
-out:
- mutex_unlock(powd->mutex);
- return noErr;
-}
-
-static int core_audio_init(struct writer_node *wn)
-{
- struct private_osx_write_data *powd = para_calloc(sizeof(*powd));
- Component comp;
- int ret;
- int32_t val;
- AURenderCallbackStruct input_callback;
- ComponentDescription desc = {
- .componentType = kAudioUnitType_Output,
- .componentSubType = kAudioUnitSubType_DefaultOutput,
- .componentManufacturer = kAudioUnitManufacturer_Apple,
- };
- AudioStreamBasicDescription format = {
- .mFormatID = kAudioFormatLinearPCM,
- .mFramesPerPacket = 1,
- };
- struct btr_node *btrn = wn->btrn;
- struct btr_node_description bnd;
-
- PARA_INFO_LOG("wn: %p\n", wn);
- ret = -E_DEFAULT_COMP;
- comp = FindNextComponent(NULL, &desc);
- if (!comp)
- goto e0;
- ret = -E_OPEN_COMP;
- if (OpenAComponent(comp, &powd->audio_unit))
- goto e0;
- ret = -E_UNIT_INIT;
- if (AudioUnitInitialize(powd->audio_unit))
- goto e1;
- get_btr_sample_rate(btrn, &val);
- powd->sample_rate = val;
- get_btr_channels(btrn, &val);
- powd->channels = val;
- get_btr_sample_format(btrn, &val);
- powd->sample_format = val;
- /*
- * Choose PCM format. We tell the Output Unit what format we're going
- * to supply data to it. This is necessary if you're providing data
- * through an input callback AND you want the DefaultOutputUnit to do
- * any format conversions necessary from your format to the device's
- * format.
- */
-
- format.mSampleRate = powd->sample_rate;
- format.mChannelsPerFrame = powd->channels;
-
- switch (powd->sample_format) {
- case SF_S8:
- case SF_U8:
- wn->min_iqs = powd->channels;
- format.mBitsPerChannel = 8;
- format.mBytesPerPacket = powd->channels;
- format.mFormatFlags |= kLinearPCMFormatFlagIsPacked;
- break;
- default:
- wn->min_iqs = powd->channels * 2;
- format.mBytesPerPacket = powd->channels * 2;
- format.mBitsPerChannel = 16;
- format.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
- }
- format.mBytesPerFrame = format.mBytesPerPacket;
-
- if (powd->sample_format == SF_S16_BE || powd->sample_format == SF_U16_BE)
- format.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
-
- input_callback = (AURenderCallbackStruct){osx_callback, wn};
- ret = -E_STREAM_FORMAT;
- if (AudioUnitSetProperty(powd->audio_unit, kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Input, 0, &format, sizeof(format)))
- goto e2;
- ret = -E_ADD_CALLBACK;
- if (AudioUnitSetProperty(powd->audio_unit, kAudioUnitProperty_SetRenderCallback,
- kAudioUnitScope_Input, 0, &input_callback,
- sizeof(input_callback)) < 0)
- goto e2;
-
- ret = mutex_new();
- if (ret < 0)
- goto e2;
- powd->mutex = ret;
- /* set up callback btr node */
- bnd.name = "cb_node";
- bnd.parent = btrn;
- bnd.child = NULL;
- bnd.handler = NULL;
- bnd.context = powd;
- powd->callback_btrn = btr_new_node(&bnd);
- wn->private_data = powd;
- return 1;
-e2:
- AudioUnitUninitialize(powd->audio_unit);
-e1:
- CloseComponent(powd->audio_unit);
-e0:
- free(powd);
- wn->private_data = NULL;
- return ret;
-}
-
-static void osx_write_close(struct writer_node *wn)
-{
- struct private_osx_write_data *powd = wn->private_data;
-
- if (!powd)
- return;
- PARA_INFO_LOG("closing writer node %p\n", wn);
- mutex_destroy(powd->mutex);
- free(powd);
- wn->private_data = NULL;
-}
-
-/* must be called with the mutex held */
-static inline bool need_drain_delay(struct private_osx_write_data *powd)
-{
- if (!powd->playing)
- return false;
- return btr_get_input_queue_size(powd->callback_btrn) != 0;
-}
-
-static void osx_write_pre_select(struct sched *s, void *context)
-{
- struct writer_node *wn = context;
- struct private_osx_write_data *powd = wn->private_data;
- int ret;
- bool drain_delay_nec = false;
-
- if (!powd) {
- ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_LEAF);
- if (ret != 0)
- sched_min_delay(s);
- return;
- }
-
- mutex_lock(powd->mutex);
- ret = btr_node_status(wn->btrn, wn->min_iqs, BTR_NT_INTERNAL);
- if (ret < 0)
- drain_delay_nec = need_drain_delay(powd);
- mutex_unlock(powd->mutex);
-
- if (drain_delay_nec)
- return sched_request_timeout_ms(50, s);
- if (ret != 0)
- return sched_min_delay(s);
- sched_request_timeout_ms(50, s);
-}
-
-static int osx_write_post_select(__a_unused struct sched *s, void *context)
-{
- struct writer_node *wn = context;
- struct private_osx_write_data *powd = wn->private_data;
- struct btr_node *btrn = wn->btrn;
- int ret;
-
- ret = task_get_notification(wn->task);
- if (ret < 0)
- goto fail;
- if (!powd) {
- ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_LEAF);
- if (ret == 0)
- return 0;
- if (ret < 0)
- goto fail;
- ret = core_audio_init(wn);
- if (ret < 0)
- goto fail;
- powd = wn->private_data;
- ret = -E_UNIT_START;
- if (AudioOutputUnitStart(powd->audio_unit) != noErr) {
- AudioUnitUninitialize(powd->audio_unit);
- CloseComponent(powd->audio_unit);
- btr_remove_node(&powd->callback_btrn);
- goto fail;
- }
- }
- mutex_lock(powd->mutex);
- ret = btr_node_status(btrn, wn->min_iqs, BTR_NT_INTERNAL);
- if (ret > 0)
- btr_pushdown(btrn);
- if (ret < 0 && need_drain_delay(powd))
- ret = 0;
- mutex_unlock(powd->mutex);
- if (ret >= 0)
- return 0;
-fail:
- assert(ret < 0);
- if (powd && powd->callback_btrn) {
- AudioOutputUnitStop(powd->audio_unit);
- AudioUnitUninitialize(powd->audio_unit);
- CloseComponent(powd->audio_unit);
- btr_remove_node(&powd->callback_btrn);
- }
- btr_remove_node(&wn->btrn);
- PARA_NOTICE_LOG("%s\n", para_strerror(-ret));
- return ret;
-}
-
-struct writer lsg_write_cmd_com_osx_user_data = {
- .close = osx_write_close,
- .pre_select = osx_write_pre_select,
- .post_select = osx_write_post_select,
-};
char *afhi_txt;
};
-typedef int (*play_cmd_handler_t)(struct play_task *pt,
- struct lls_parse_result *lpr);
+typedef int (*play_cmd_handler_t)(struct lls_parse_result *lpr);
struct play_command_info {
play_cmd_handler_t handler;
};
char *stat_item_values[NUM_STAT_ITEMS] = {NULL};
static struct sched sched = {.max_fileno = 0};
-static struct play_task play_task;
+static struct play_task play_task, *pt = &play_task;
#define AFH_RECV_CMD (lls_cmd(LSG_RECV_CMD_CMD_AFH, recv_cmd_suite))
#define AFH_RECV ((struct receiver *)lls_user_data(AFH_RECV_CMD))
exit(EXIT_FAILURE);
}
-static char get_playback_state(struct play_task *pt)
+static char get_playback_state(void)
{
switch (pt->rq) {
case CRT_NONE: return pt->playing? 'P' : 'U';
assert(false);
};
-static long unsigned get_play_time(struct play_task *pt)
+static long unsigned get_play_time(void)
{
- char state = get_playback_state(pt);
+ char state = get_playback_state();
long unsigned result;
if (state != 'P' && state != 'U')
}
-static void wipe_receiver_node(struct play_task *pt)
+static void wipe_receiver_node(void)
{
PARA_NOTICE_LOG("cleaning up receiver node\n");
btr_remove_node(&pt->rn.btrn);
}
/* returns: 0 not eof, 1: eof, < 0: fatal error. */
-static int get_playback_error(struct play_task *pt)
+static int get_playback_error(void)
{
int err;
return err;
}
-static int eof_cleanup(struct play_task *pt)
+static int eof_cleanup(void)
{
const struct filter *decoder;
const struct writer *w = writer_get(-1); /* default writer */
int ret;
- ret = get_playback_error(pt);
+ ret = get_playback_error();
if (ret == 0)
return ret;
PARA_NOTICE_LOG("cleaning up wn/fn nodes\n");
* paused.
*/
if (ret < 0)
- wipe_receiver_node(pt);
+ wipe_receiver_node();
return ret;
}
.handler = AFH_RECV->execute));
}
-static int open_new_file(struct play_task *pt)
+static int open_new_file(void)
{
int ret;
const char *path = get_playlist_file(pt->next_file);
char *argv[] = {"play", "-f", tmp, "-b", "0", NULL};
PARA_NOTICE_LOG("next file: %s\n", path);
- wipe_receiver_node(pt);
+ wipe_receiver_node();
pt->start_chunk = 0;
pt->rn.btrn = new_recv_btrn(&pt->rn);
ret = lls(lls_parse(ARRAY_SIZE(argv) - 1, argv, AFH_RECV_CMD,
}
return 1;
fail:
- wipe_receiver_node(pt);
+ wipe_receiver_node();
return ret;
}
-static int load_file(struct play_task *pt)
+static int load_file(void)
{
const char *af;
char *tmp, buf[20];
btr_remove_node(&pt->rn.btrn);
if (!pt->rn.receiver || pt->next_file != pt->current_file) {
- ret = open_new_file(pt);
+ ret = open_new_file();
if (ret < 0)
return ret;
} else {
register_writer_node(&pt->wn, pt->fn.btrn, &sched);
return 1;
fail:
- wipe_receiver_node(pt);
+ wipe_receiver_node();
return ret;
}
-static int next_valid_file(struct play_task *pt)
+static int next_valid_file(void)
{
int i, j = pt->current_file;
unsigned num_inputs = lls_num_inputs(play_lpr);
return -E_NO_VALID_FILES;
}
-static int load_next_file(struct play_task *pt)
+static int load_next_file(void)
{
int ret;
again:
if (pt->rq == CRT_NONE) {
pt->start_chunk = 0;
- ret = next_valid_file(pt);
+ ret = next_valid_file();
if (ret < 0)
return ret;
pt->next_file = ret;
} else if (pt->rq == CRT_REPOS)
pt->next_file = pt->current_file;
- ret = load_file(pt);
+ ret = load_file();
if (ret < 0) {
PARA_ERROR_LOG("%s: marking file as invalid\n",
para_strerror(-ret));
return ret;
}
-static void kill_stream(struct play_task *pt)
+static void kill_stream(void)
{
if (pt->wn.task)
task_notify(pt->wn.task, E_EOF);
#ifdef HAVE_READLINE
/* only called from com_prev(), nec. only if we have readline */
-static int previous_valid_file(struct play_task *pt)
+static int previous_valid_file(void)
{
int i, j = pt->current_file;
unsigned num_inputs = lls_num_inputs(play_lpr);
I9E_DUMMY_COMPLETER(info);
I9E_DUMMY_COMPLETER(play);
I9E_DUMMY_COMPLETER(pause);
-I9E_DUMMY_COMPLETER(stop);
I9E_DUMMY_COMPLETER(tasks);
I9E_DUMMY_COMPLETER(quit);
I9E_DUMMY_COMPLETER(ff);
{.name = NULL}
};
-static void attach_stdout(struct play_task *pt, const char *name)
+static void attach_stdout(const char *name)
{
if (pt->btrn)
return;
i9e_attach_to_stdout(pt->btrn);
}
-static void detach_stdout(struct play_task *pt)
+static void detach_stdout(void)
{
btr_remove_node(&pt->btrn);
}
-static int com_quit(struct play_task *pt,
- __a_unused struct lls_parse_result *lpr)
+static int com_quit(__a_unused struct lls_parse_result *lpr)
{
pt->rq = CRT_TERM_RQ;
return 0;
}
EXPORT_PLAY_CMD_HANDLER(quit);
-static int com_help(struct play_task *pt, struct lls_parse_result *lpr)
+static int com_help(struct lls_parse_result *lpr)
{
int i, ret;
char *buf, *errctx;
}
EXPORT_PLAY_CMD_HANDLER(help);
-static int com_info(struct play_task *pt,
- __a_unused struct lls_parse_result *lpr)
+static int com_info(__a_unused struct lls_parse_result *lpr)
{
char *buf;
size_t sz;
}
EXPORT_PLAY_CMD_HANDLER(info);
-static void list_file(struct play_task *pt, int num)
+static void list_file(int num)
{
char *buf;
size_t sz;
btr_add_output(buf, sz, pt->btrn);
}
-static int com_tasks(struct play_task *pt,
- __a_unused struct lls_parse_result *lpr)
+static int com_tasks(__a_unused struct lls_parse_result *lpr)
{
static char state;
char *buf;
buf = get_task_list(&sched);
btr_add_output(buf, strlen(buf), pt->btrn);
- state = get_playback_state(pt);
+ state = get_playback_state();
sz = xasprintf(&buf, "state: %c\n", state);
btr_add_output(buf, sz, pt->btrn);
return 0;
}
EXPORT_PLAY_CMD_HANDLER(tasks);
-static int com_ls(struct play_task *pt,
- __a_unused struct lls_parse_result *lpr)
+static int com_ls(__a_unused struct lls_parse_result *lpr)
{
int i;
unsigned num_inputs = lls_num_inputs(play_lpr);
for (i = 0; i < num_inputs; i++)
- list_file(pt, i);
+ list_file(i);
return 0;
}
EXPORT_PLAY_CMD_HANDLER(ls);
-static int com_play(struct play_task *pt, struct lls_parse_result *lpr)
+static int com_play(struct lls_parse_result *lpr)
{
int32_t x;
int ret;
free(errctx);
return ret;
}
- state = get_playback_state(pt);
+ state = get_playback_state();
if (lls_num_inputs(lpr) == 0) {
if (state == 'P')
return 0;
return ret;
if (x < 0 || x >= lls_num_inputs(play_lpr))
return -ERRNO_TO_PARA_ERROR(EINVAL);
- kill_stream(pt);
+ kill_stream();
pt->next_file = x;
pt->rq = CRT_FILE_CHANGE;
return 0;
}
EXPORT_PLAY_CMD_HANDLER(play);
-static int com_pause(struct play_task *pt,
- __a_unused struct lls_parse_result *lpr)
+static int com_pause(__a_unused struct lls_parse_result *lpr)
{
char state;
long unsigned seconds, ss;
- state = get_playback_state(pt);
+ state = get_playback_state();
pt->playing = false;
if (state != 'P')
return 0;
- seconds = get_play_time(pt);
+ seconds = get_play_time();
pt->playing = false;
ss = 0;
if (pt->seconds > 0)
ss = PARA_MAX(ss, 0UL);
ss = PARA_MIN(ss, pt->num_chunks);
pt->start_chunk = ss;
- kill_stream(pt);
+ kill_stream();
return 0;
}
EXPORT_PLAY_CMD_HANDLER(pause);
-static int com_prev(struct play_task *pt,
- __a_unused struct lls_parse_result *lpr)
+static int com_prev(__a_unused struct lls_parse_result *lpr)
{
int ret;
- ret = previous_valid_file(pt);
+ ret = previous_valid_file();
if (ret < 0)
return ret;
- kill_stream(pt);
+ kill_stream();
pt->next_file = ret;
pt->rq = CRT_FILE_CHANGE;
pt->start_chunk = 0;
}
EXPORT_PLAY_CMD_HANDLER(prev);
-static int com_next(struct play_task *pt,
- __a_unused struct lls_parse_result *lpr)
+static int com_next(__a_unused struct lls_parse_result *lpr)
{
int ret;
- ret = next_valid_file(pt);
+ ret = next_valid_file();
if (ret < 0)
return ret;
- kill_stream(pt);
+ kill_stream();
pt->next_file = ret;
pt->rq = CRT_FILE_CHANGE;
pt->start_chunk = 0;
}
EXPORT_PLAY_CMD_HANDLER(next);
-static int com_fg(struct play_task *pt,
- __a_unused struct lls_parse_result *lpr)
+static int com_fg(__a_unused struct lls_parse_result *lpr)
{
pt->background = false;
return 0;
}
EXPORT_PLAY_CMD_HANDLER(fg);
-static int com_bg(struct play_task *pt,
- __a_unused struct lls_parse_result *lpr)
+static int com_bg(__a_unused struct lls_parse_result *lpr)
{
pt->background = true;
return 0;
}
EXPORT_PLAY_CMD_HANDLER(bg);
-static int com_jmp(struct play_task *pt, struct lls_parse_result *lpr)
+static int com_jmp(struct lls_parse_result *lpr)
{
int32_t percent;
int ret;
if (percent < 0 || percent > 100)
return -ERRNO_TO_PARA_ERROR(EINVAL);
if (percent == 100)
- return com_next(pt, NULL);
+ return com_next(NULL);
if (pt->playing && !pt->fn.btrn)
return 0;
pt->start_chunk = percent * pt->num_chunks / 100;
if (!pt->playing)
return 0;
pt->rq = CRT_REPOS;
- kill_stream(pt);
+ kill_stream();
return 0;
}
EXPORT_PLAY_CMD_HANDLER(jmp);
-static int com_ff(struct play_task *pt, struct lls_parse_result *lpr)
+static int com_ff(struct lls_parse_result *lpr)
{
int32_t seconds;
char *errctx;
return ret;
if (pt->playing && !pt->fn.btrn)
return 0;
- seconds += get_play_time(pt);
+ seconds += get_play_time();
seconds = PARA_MIN(seconds, (typeof(seconds))pt->seconds - 4);
seconds = PARA_MAX(seconds, 0);
pt->start_chunk = pt->num_chunks * seconds / pt->seconds;
if (!pt->playing)
return 0;
pt->rq = CRT_REPOS;
- kill_stream(pt);
+ kill_stream();
return 0;
}
EXPORT_PLAY_CMD_HANDLER(ff);
-static int run_command(char *line, struct play_task *pt)
+static int run_command(char *line)
{
int ret, argc;
char **argv = NULL;
struct lls_parse_result *lpr;
const struct lls_command *cmd;
- attach_stdout(pt, __FUNCTION__);
+ attach_stdout(__FUNCTION__);
ret = create_argv(line, " ", &argv);
if (ret < 0)
goto out;
if (ret < 0)
goto out;
pci = lls_user_data(cmd);
- ret = pci->handler(pt, lpr);
+ ret = pci->handler(lpr);
lls_free_parse_result(lpr, cmd);
out:
if (errctx)
static int play_i9e_line_handler(char *line)
{
- return run_command(line, &play_task);
+ return run_command(line);
}
static int play_i9e_key_handler(int key)
{
- struct play_task *pt = &play_task;
int idx = get_key_map_idx(key);
char *seq = get_key_map_seq(key);
char *cmd = get_key_map_cmd(key);
PARA_NOTICE_LOG("pressed %d: %s key #%d (%s -> %s)\n",
key, internal? "internal" : "user-defined",
idx, seq, cmd);
- run_command(cmd, pt);
+ run_command(cmd);
free(seq);
free(cmd);
pt->next_update = *now;
static void sigint_handler(int sig)
{
- play_task.background = true;
+ pt->background = true;
i9e_signal_dispatch(sig);
}
* stderr. Once the i9e subsystem has been initialized, we switch to the i9e
* log facility.
*/
-static void session_open(struct play_task *pt)
+static void session_open(void)
{
int ret;
char *history_file;
exit(EXIT_FAILURE);
}
-static void session_update_time_string(struct play_task *pt, char *str, unsigned len)
+static void session_update_time_string(char *str, unsigned len)
{
if (pt->background)
return;
* terminates. Subsequent calls to i9e_get_error() then return negative and we
* are allowed to call i9e_close() and terminate as well.
*/
-static int session_post_select(__a_unused struct sched *s, struct play_task *pt)
+static int session_post_select(__a_unused struct sched *s)
{
int ret;
if (pt->background)
- detach_stdout(pt);
+ detach_stdout();
else
- attach_stdout(pt, __FUNCTION__);
+ attach_stdout(__FUNCTION__);
ret = i9e_get_error();
if (ret < 0) {
- kill_stream(pt);
+ kill_stream();
i9e_close();
para_log = stderr_log;
free(ici.history_file);
return ret;
}
- if (get_playback_state(pt) == 'X')
+ if (get_playback_state() == 'X')
i9e_signal_dispatch(SIGTERM);
return 0;
}
#else /* HAVE_READLINE */
-static int session_post_select(struct sched *s, struct play_task *pt)
+static int session_post_select(struct sched *s)
{
char c;
return 0;
if (read(STDIN_FILENO, &c, 1))
do_nothing;
- kill_stream(pt);
+ kill_stream();
return 1;
}
-static void session_open(__a_unused struct play_task *pt)
+static void session_open(void)
{
}
-static void session_update_time_string(__a_unused struct play_task *pt,
- char *str, __a_unused unsigned len)
+static void session_update_time_string(char *str, __a_unused unsigned len)
{
printf("\r%s ", str);
fflush(stdout);
}
#endif /* HAVE_READLINE */
-static void play_pre_select(struct sched *s, void *context)
+static void play_pre_select(struct sched *s, __a_unused void *context)
{
- struct play_task *pt = context;
char state;
para_fd_set(STDIN_FILENO, &s->rfds, &s->max_fileno);
- state = get_playback_state(pt);
+ state = get_playback_state();
if (state == 'R' || state == 'F' || state == 'X')
return sched_min_delay(s);
sched_request_barrier_or_min_delay(&pt->next_update, s);
}
-static unsigned get_time_string(struct play_task *pt, char **result)
+static unsigned get_time_string(char **result)
{
int seconds, length;
- char state = get_playback_state(pt);
+ char state = get_playback_state();
/* do not return anything if things are about to change */
if (state != 'P' && state != 'U') {
length = pt->seconds;
if (length == 0)
return xasprintf(result, "0:00 [0:00] (0%%/0:00)");
- seconds = get_play_time(pt);
+ seconds = get_play_time();
return xasprintf(result, "#%u: %d:%02d [%d:%02d] (%d%%/%d:%02d) %s",
pt->current_file,
seconds / 60,
);
}
-static int play_post_select(struct sched *s, void *context)
+static int play_post_select(struct sched *s, __a_unused void *context)
{
- struct play_task *pt = context;
int ret;
- ret = eof_cleanup(pt);
+ ret = eof_cleanup();
if (ret < 0) {
pt->rq = CRT_TERM_RQ;
return 0;
}
- ret = session_post_select(s, pt);
+ ret = session_post_select(s);
if (ret < 0)
goto out;
if (!pt->wn.btrn && !pt->fn.btrn) {
- char state = get_playback_state(pt);
+ char state = get_playback_state();
if (state == 'P' || state == 'R' || state == 'F') {
PARA_NOTICE_LOG("state: %c\n", state);
- ret = load_next_file(pt);
+ ret = load_next_file();
if (ret < 0) {
PARA_ERROR_LOG("%s\n", para_strerror(-ret));
pt->rq = CRT_TERM_RQ;
}
if (tv_diff(now, &pt->next_update, NULL) >= 0) {
char *str;
- unsigned len = get_time_string(pt, &str);
+ unsigned len = get_time_string(&str);
struct timeval delay = {.tv_sec = 0, .tv_usec = 100 * 1000};
if (str && len > 0)
- session_update_time_string(pt, str, len);
+ session_update_time_string(str, len);
free(str);
tv_add(now, &delay, &pt->next_update);
}
int main(int argc, char *argv[])
{
int ret;
- struct play_task *pt = &play_task;
unsigned num_inputs;
/* needed this early to make help work */
sched.default_timeout.tv_sec = 5;
parse_config_or_die(argc, argv);
AFH_RECV->init();
- session_open(pt);
+ session_open();
num_inputs = lls_num_inputs(play_lpr);
init_shuffle_map();
pt->invalid = para_calloc(sizeof(*pt->invalid) * num_inputs);