commit 791d3db313f1f9816c699583c97079efccd408d6 from: Omar Polo date: Sat Jul 09 07:34:36 2022 UTC implement seeking This adds the internal management of the seeking, as well as the decoder backends bits. 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 #include #include +#include #include #include @@ -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, ¤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 @@ -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; }