Commit Diff


commit - 2ddcfa406b99caba54c85f55c0b4294695fb2e05
commit + 791d3db313f1f9816c699583c97079efccd408d6
blob - e660fc961b1df995c0228e4b06ca353fb295362f
blob + 238295db07b7cbc0d8793381b38d5936f4dec604
--- amused.c
+++ amused.c
@@ -380,9 +380,9 @@ imsg_compose_event(struct imsgev *iev, uint16_t type, 
 }
 
 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
@@ -409,7 +409,7 @@ main_play_song(const char *path)
 	}
 
 	play_state = STATE_PLAYING;
-	main_send_player(IMSG_PLAY, fd);
+	main_send_player(IMSG_PLAY, fd, NULL, 0);
 	return 1;
 }
 
@@ -438,7 +438,7 @@ main_playlist_jump(struct imsgev *iev, struct imsg *im
 		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
@@ -47,6 +47,7 @@ enum imsg_type {
 	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 */
@@ -82,8 +83,14 @@ enum actions {
 	JUMP,
 	REPEAT,
 	MONITOR,
+	SEEK,
 };
 
+struct player_seek {
+	int64_t	offset;
+	int	relative;
+};
+
 struct ctl_command;
 
 struct player_repeat {
@@ -106,6 +113,7 @@ struct parse_result {
 	int			 pretty;
 	int			 monitor[IMSG__LAST];
 	struct player_repeat	 rep;
+	struct player_seek	 seek;
 	struct ctl_command	*ctl;
 };
 
@@ -124,7 +132,7 @@ void		spawn_daemon(void);
 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);
@@ -143,7 +151,8 @@ __dead void	ctl(int, char **);
 /* 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
@@ -287,7 +287,7 @@ control_dispatch_imsg(int fd, short event, void *bula)
 				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);
@@ -299,11 +299,11 @@ control_dispatch_imsg(int fd, short event, void *bula)
 				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);
@@ -312,18 +312,18 @@ control_dispatch_imsg(int fd, short event, void *bula)
 			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;
@@ -338,12 +338,12 @@ control_dispatch_imsg(int fd, short event, void *bula)
 			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;
@@ -404,6 +404,17 @@ control_dispatch_imsg(int fd, short event, void *bula)
 		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
@@ -141,10 +141,18 @@ player_onmove(void *arg, int delta)
 	}
 }
 
+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;
@@ -182,6 +190,20 @@ again:
 	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);
 	}
@@ -254,20 +276,20 @@ err:
 }
 
 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:
@@ -278,11 +300,12 @@ player_shouldstop(void)
 }
 
 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);
@@ -290,7 +313,7 @@ play(const void *buf, size_t len)
 			fatal("poll");
 
 		if (player_pfds[0].revents & (POLLHUP|POLLIN)) {
-			if (player_shouldstop()) {
+			if (player_shouldstop(s)) {
 				sio_flush(hdl);
 				stopped = 1;
 				return 0;
@@ -359,7 +382,7 @@ player(int debug, int verbose)
 		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
@@ -54,6 +54,7 @@ play_mp3(int fd, const char **errstr)
 	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)
@@ -71,6 +72,15 @@ play_mp3(int fd, const char **errstr)
 	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:
@@ -81,7 +91,7 @@ play_mp3(int fd, const char **errstr)
 				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
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <string.h>
 #include <imsg.h>
 
 #include <FLAC/stream_decoder.h>
@@ -32,11 +33,31 @@
 #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;
 
@@ -45,8 +66,14 @@ writecb(const FLAC__StreamDecoder *decoder, const FLAC
 
 	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;
 		}
 
@@ -73,9 +100,12 @@ writecb(const FLAC__StreamDecoder *decoder, const FLAC
 		}
 	}
 
-	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;
@@ -112,6 +142,7 @@ int
 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;
@@ -125,21 +156,24 @@ play_flac(int fd, const char **errstr)
 
 	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
@@ -46,6 +46,7 @@ play_oggvorbis(int fd, const char **errstr)
 	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)
@@ -71,13 +72,20 @@ play_oggvorbis(int fd, const char **errstr)
 	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,
 		    &current_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
@@ -45,6 +45,7 @@ play_opus(int fd, const char **errstr)
 	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;
@@ -59,6 +60,13 @@ play_opus(int fd, const char **errstr)
 	}
 
 	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? */
@@ -92,7 +100,7 @@ play_opus(int fd, const char **errstr)
 			out[2*i+1] = (pcm[i] >> 8) & 0xFF;
 		}
 
-		if (!play(out, 4*r)) {
+		if (!play(out, 4*r, &seek)) {
 			ret = 1;
 			break;
 		}