commit - 2ddcfa406b99caba54c85f55c0b4294695fb2e05
commit + 791d3db313f1f9816c699583c97079efccd408d6
blob - e660fc961b1df995c0228e4b06ca353fb295362f
blob + 238295db07b7cbc0d8793381b38d5936f4dec604
--- amused.c
+++ amused.c
}
int
-main_send_player(uint16_t type, int fd)
+main_send_player(uint16_t type, int fd, const void *data, size_t len)
{
- return imsg_compose_event(iev_player, type, 0, 0, fd, NULL, 0);
+ return imsg_compose_event(iev_player, type, 0, 0, fd, data, len);
}
int
}
play_state = STATE_PLAYING;
- main_send_player(IMSG_PLAY, fd);
+ main_send_player(IMSG_PLAY, fd, NULL, 0);
return 1;
}
return;
}
- main_send_player(IMSG_STOP, -1);
+ main_send_player(IMSG_STOP, -1, NULL, 0);
if (!main_play_song(song)) {
main_senderr(iev, "can't play");
playlist_dropcurrent();
blob - 7792f83ab45661a016c724e838e8b4a768c36b96
blob + 5bfef5817b5b06a34ca123c200879905a1161b6a
--- amused.h
+++ amused.h
IMSG_CTL_PREV,
IMSG_CTL_JUMP,
IMSG_CTL_REPEAT, /* struct player_repeat */
+ IMSG_CTL_SEEK, /* struct player_seek */
IMSG_CTL_BEGIN,
IMSG_CTL_ADD, /* path to a file */
JUMP,
REPEAT,
MONITOR,
+ SEEK,
};
+struct player_seek {
+ int64_t offset;
+ int relative;
+};
+
struct ctl_command;
struct player_repeat {
int pretty;
int monitor[IMSG__LAST];
struct player_repeat rep;
+ struct player_seek seek;
struct ctl_command *ctl;
};
void imsg_event_add(struct imsgev *iev);
int imsg_compose_event(struct imsgev *, uint16_t, uint32_t,
pid_t, int, const void *, uint16_t);
-int main_send_player(uint16_t, int);
+int main_send_player(uint16_t, int, const void *, size_t);
int main_play_song(const char *);
void main_playlist_jump(struct imsgev *, struct imsg *);
void main_playlist_resume(void);
/* player.c */
int player_setup(unsigned int, unsigned int, unsigned int);
void player_setduration(int64_t);
-int play(const void *, size_t);
+void player_setpos(int64_t);
+int play(const void *, size_t, int64_t *);
int player(int, int);
int play_oggvorbis(int, const char **);
blob - 0484778f8774d82944b106cc4ec02de16b8c1ea7
blob + 18ed3f53e3a54dcdd447f20a3774e35847c68258
--- control.c
+++ control.c
break;
case STATE_PAUSED:
play_state = STATE_PLAYING;
- main_send_player(IMSG_RESUME, -1);
+ main_send_player(IMSG_RESUME, -1, NULL ,0);
break;
}
control_notify(&c->iev, imsg.hdr.type);
break;
case STATE_PLAYING:
play_state = STATE_PAUSED;
- main_send_player(IMSG_PAUSE, -1);
+ main_send_player(IMSG_PAUSE, -1, NULL, 0);
break;
case STATE_PAUSED:
play_state = STATE_PLAYING;
- main_send_player(IMSG_RESUME, -1);
+ main_send_player(IMSG_RESUME, -1, NULL, 0);
break;
}
control_notify(&c->iev, imsg.hdr.type);
if (play_state != STATE_PLAYING)
break;
play_state = STATE_PAUSED;
- main_send_player(IMSG_PAUSE, -1);
+ main_send_player(IMSG_PAUSE, -1, NULL, 0);
control_notify(&c->iev, imsg.hdr.type);
break;
case IMSG_CTL_STOP:
if (play_state == STATE_STOPPED)
break;
play_state = STATE_STOPPED;
- main_send_player(IMSG_STOP, -1);
+ main_send_player(IMSG_STOP, -1, NULL, 0);
control_notify(&c->iev, imsg.hdr.type);
break;
case IMSG_CTL_RESTART:
- main_send_player(IMSG_STOP, -1);
+ main_send_player(IMSG_STOP, -1, NULL, 0);
main_restart_track();
control_notify(&c->iev, imsg.hdr.type);
break;
main_send_status(&c->iev);
break;
case IMSG_CTL_NEXT:
- main_send_player(IMSG_STOP, -1);
+ main_send_player(IMSG_STOP, -1, NULL, 0);
main_playlist_advance();
control_notify(&c->iev, imsg.hdr.type);
break;
case IMSG_CTL_PREV:
- main_send_player(IMSG_STOP, -1);
+ main_send_player(IMSG_STOP, -1, NULL, 0);
main_playlist_previous();
control_notify(&c->iev, imsg.hdr.type);
break;
case IMSG_CTL_MONITOR:
c->monitor = 1;
break;
+ case IMSG_CTL_SEEK:
+ if (IMSG_DATA_SIZE(imsg) !=
+ sizeof(struct player_seek)) {
+ main_senderr(&c->iev, "wrong size");
+ break;
+ }
+ log_debug("got IMSG_CTL_SEEK, forwarding it");
+ main_send_player(IMSG_CTL_SEEK, -1, imsg.data,
+ IMSG_DATA_SIZE(imsg));
+ control_notify(&c->iev, imsg.hdr.type);
+ break;
default:
log_debug("%s: error handling imsg %d", __func__,
imsg.hdr.type);
blob - e10b6c193f104eaf4b87bae5734d77b41ebf13f1
blob + 360762778cc98ec5c3b3976f84f2af73b6b1fb8a
--- player.c
+++ player.c
}
}
+void
+player_setpos(int64_t pos)
+{
+ samples = pos;
+ player_onmove(NULL, 0);
+}
+
/* process only one message */
static int
-player_dispatch(void)
+player_dispatch(int64_t *s)
{
+ struct player_seek seek;
struct pollfd pfd;
struct imsg imsg;
ssize_t n;
case IMSG_PAUSE:
case IMSG_STOP:
break;
+ case IMSG_CTL_SEEK:
+ if (s == NULL)
+ break;
+ if (IMSG_DATA_SIZE(imsg) != sizeof(seek))
+ fatalx("wrong size for seek ctl");
+ memcpy(&seek, imsg.data, sizeof(seek));
+ log_debug("got to seek: {%lld, %d}", seek.offset,
+ seek.relative);
+ *s = seek.offset * par.rate;
+ if (seek.relative)
+ *s += samples;
+ if (*s < 0)
+ *s = -1;
+ break;
default:
fatalx("unknown imsg %d", imsg.hdr.type);
}
}
static int
-player_pause(void)
+player_pause(int64_t *s)
{
int r;
- r = player_dispatch();
+ r = player_dispatch(s);
return r == IMSG_RESUME;
}
static int
-player_shouldstop(void)
+player_shouldstop(int64_t *s)
{
- switch (player_dispatch()) {
+ switch (player_dispatch(s)) {
case IMSG_PAUSE:
- if (player_pause())
+ if (player_pause(s))
break;
/* fallthrough */
case IMSG_STOP:
}
int
-play(const void *buf, size_t len)
+play(const void *buf, size_t len, int64_t *s)
{
size_t w;
int nfds, revents, r;
+ *s = -1;
while (len != 0) {
nfds = sio_pollfd(hdl, player_pfds + 1, POLLOUT);
r = poll(player_pfds, nfds + 1, INFTIM);
fatal("poll");
if (player_pfds[0].revents & (POLLHUP|POLLIN)) {
- if (player_shouldstop()) {
+ if (player_shouldstop(s)) {
sio_flush(hdl);
stopped = 1;
return 0;
const char *errstr = NULL;
while (nextfd == -1)
- player_dispatch();
+ player_dispatch(NULL);
r = player_playnext(&errstr);
if (r == -1)
blob - 64e5452d7f2e271272ce6f375187a95109068027
blob + ddf86c28d7b98f0a796b5ffa55cd87f02b4c673b
--- player_123.c
+++ player_123.c
static char buf[4096];
size_t len;
mpg123_handle *mh;
+ int64_t seek = -1;
int err, ret = -1;
if ((mh = mpg123_new(NULL, NULL)) == NULL)
player_setduration(mpg123_length(mh));
for (;;) {
+ if (seek != -1) {
+ seek = mpg123_seek(mh, seek, SEEK_SET);
+ if (seek < 0) {
+ ret = 0;
+ break;
+ }
+ player_setpos(seek);
+ }
+
err = mpg123_read(mh, buf, sizeof(buf), &len);
switch (err) {
case MPG123_DONE:
goto done;
break;
case MPG123_OK:
- if (!play(buf, len)) {
+ if (!play(buf, len, &seek)) {
ret = 1;
goto done;
}
blob - 58fc73e10d2b517e8e87573da6fcf6e743f3b86e
blob + fb7d7f6e5fb27589c7b28218ed1c71c88c7091f6
--- player_flac.c
+++ player_flac.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#include <string.h>
#include <imsg.h>
#include <FLAC/stream_decoder.h>
#include "amused.h"
#include "log.h"
+struct write_args {
+ FLAC__StreamDecoder *decoder;
+ int seek_failed;
+};
+
+static int
+sample_seek(struct write_args *wa, int64_t seek)
+{
+ int ok;
+
+ ok = FLAC__stream_decoder_seek_absolute(wa->decoder, seek);
+ if (ok)
+ player_setpos(seek);
+ else
+ wa->seek_failed = 1;
+ return ok;
+}
+
static FLAC__StreamDecoderWriteStatus
writecb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
const int32_t * const *src, void *data)
{
+ struct write_args *wa = data;
static uint8_t buf[BUFSIZ];
+ int64_t seek;
int c, i, bps, chans;
size_t len;
for (i = 0, len = 0; i < frame->header.blocksize; ++i) {
if (len + 4*chans >= sizeof(buf)) {
- if (!play(buf, len))
+ if (!play(buf, len, &seek))
goto quit;
+ if (seek != -1) {
+ if (sample_seek(wa, seek))
+ break;
+ else
+ goto quit;
+ }
len = 0;
}
}
}
- if (len != 0 && !play(buf, len))
+ if (len != 0 && !play(buf, len, &seek))
goto quit;
+ if (seek != -1 && !sample_seek(wa, seek))
+ goto quit;
+
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
quit:
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
play_flac(int fd, const char **errstr)
{
FILE *f;
+ struct write_args wa;
int s, ok = 1;
FLAC__StreamDecoder *decoder = NULL;
FLAC__StreamDecoderInitStatus init_status;
FLAC__stream_decoder_set_md5_checking(decoder, 1);
+ memset(&wa, 0, sizeof(wa));
+ wa.decoder = decoder;
+
init_status = FLAC__stream_decoder_init_FILE(decoder, f, writecb,
- metacb, errcb, NULL);
+ metacb, errcb, &wa);
if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
errx(1, "flac decoder: %s",
FLAC__StreamDecoderInitStatusString[init_status]);
ok = FLAC__stream_decoder_process_until_end_of_stream(decoder);
- s = FLAC__stream_decoder_get_state(decoder);
+ s = FLAC__stream_decoder_get_state(decoder);
FLAC__stream_decoder_delete(decoder);
fclose(f);
- if (s == FLAC__STREAM_DECODER_ABORTED)
+ if (s == FLAC__STREAM_DECODER_ABORTED && !wa.seek_failed)
return 1;
- else if (!ok) {
+ else if (!ok && !wa.seek_failed) {
*errstr = "flac decoding error";
return -1;
} else
blob - 218771d35ea22a6ad324b2cc6aadfe4d4d72cd9d
blob + a2263c30c54ee0d24dcd7a852cfeb7f91a4211cd
--- player_oggvorbis.c
+++ player_oggvorbis.c
FILE *f;
OggVorbis_File vf;
vorbis_info *vi;
+ int64_t seek = -1;
int current_section, eof = 0, ret = 0;
if ((f = fdopen(fd, "r")) == NULL)
while (!eof) {
long r;
+ if (seek != -1) {
+ r = ov_pcm_seek(&vf, seek);
+ if (r != 0)
+ break;
+ player_setpos(seek);
+ }
+
r = ov_read(&vf, pcmout, sizeof(pcmout), 0, 2, 1,
¤t_section);
if (r == 0)
eof = 1;
else if (r > 0) {
/* TODO: deal with sample rate changes */
- if (!play(pcmout, r)) {
+ if (!play(pcmout, r, &seek)) {
ret = 1;
break;
}
blob - 2df2f10b98c6f44843387b38112266d3bbe9d1e5
blob + 2a20b6840acc75e98eab54cbc2c4ffe84faeafe2
--- player_opus.c
+++ player_opus.c
static uint8_t out[BUFSIZ * 2];
OggOpusFile *of;
void *f;
+ int64_t seek = -1;
int r, ret = 0;
OpusFileCallbacks cb = {NULL, NULL, NULL, NULL};
int i, li, prev_li = -1, duration_set = 0;
}
for (;;) {
+ if (seek != -1) {
+ r = op_pcm_seek(of, seek);
+ if (r != 0)
+ break;
+ player_setpos(seek);
+ }
+
/* NB: will downmix multichannels files into two channels */
r = op_read_stereo(of, pcm, nitems(pcm));
if (r == OP_HOLE) /* corrupt file segment? */
out[2*i+1] = (pcm[i] >> 8) & 0xFF;
}
- if (!play(out, 4*r)) {
+ if (!play(out, 4*r, &seek)) {
ret = 1;
break;
}