From b7ca9078f627f5e5c34e0f8db495e8eff50fed73 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Sat, 21 Nov 2020 07:44:22 +1030 Subject: [PATCH] Save play position when a new track starts and restore it on restart. --- dbindex.c | 30 +++++++++++++++++--- dbindex.h | 15 ++++++++++ music-player.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 113 insertions(+), 6 deletions(-) diff --git a/dbindex.c b/dbindex.c index 631f255..8309a6b 100644 --- a/dbindex.c +++ b/dbindex.c @@ -214,6 +214,32 @@ void dbindex_abort(MDB_txn *tx) { mdb_txn_abort(tx); } +int dbstate_get(MDB_txn *tx, dbindex *db, dbstate *s) { + MDB_val key = { .mv_data = "state", .mv_size = strlen("state") }; + MDB_val data; + + db->res = mdb_get(tx, db->meta, &key, &data); + + if (db->res == 0) { + dbstate *p = (dbstate *)data.mv_data; + if (p->size != sizeof(dbstate)) + return MDB_NOTFOUND; + *s = *p; + return 0; + } + + return db->res; +} + +int dbstate_put(MDB_txn *tx, dbindex *db, dbstate *s) { + MDB_val key = { .mv_data = "state", .mv_size = strlen("state") }; + MDB_val data = { .mv_data = s, .mv_size = sizeof(*s) }; + + s->size = sizeof(dbstate); + + return mdb_put(tx, db->meta, &key, &data, 0); +} + // get by_path key static char *dbfile_path(dbfile *f) { char *path = malloc(strlen(f->path) + 9); @@ -725,10 +751,6 @@ void dbshuffle_init(dbindex *db) { Player support functions */ -// A way to iterate through a lit of files, based on an index or something else -struct dblist { -}; - #include #include #include diff --git a/dbindex.h b/dbindex.h index 788bb92..a9e2bbf 100644 --- a/dbindex.h +++ b/dbindex.h @@ -46,6 +46,17 @@ struct dbfile { char *artist; // music artist }; +/* player state, this is passed around as a struct */ +typedef struct dbstate dbstate; + +struct dbstate { + uint32_t size; // don't need to initialise + uint32_t state; // some info on playing + uint32_t fileid; // file being played + uint64_t pos; // last approximate position + time_t stamp; // last update time +}; + typedef struct dbindex dbindex; typedef struct MDB_txn dbtxn; typedef struct dbscan dbscan; @@ -57,6 +68,10 @@ dbtxn *dbindex_begin(dbindex *db, dbtxn *txn, int readonly); void dbindex_commit(dbtxn *tx); void dbindex_abort(dbtxn *tx); +int dbstate_get(dbtxn *tx, dbindex *db, dbstate *s); +int dbstate_put(dbtxn *tx, dbindex *db, dbstate *s); + +dbdisk *dbdisk_get(dbtxn *tx, dbindex *db, int diskid); dbdisk *dbdisk_get_uuid(dbtxn *tx, dbindex *db, const char *uuid); void dbdisk_free(dbdisk *d); int dbdisk_add(dbtxn *txn, dbindex *db, dbdisk *d); diff --git a/music-player.c b/music-player.c index 70e02d2..37ca7f1 100644 --- a/music-player.c +++ b/music-player.c @@ -110,6 +110,7 @@ struct audio_player { dbindex *index; dbfile *playing; char *playing_path; + dbstate playing_state; int quit; int paused; @@ -146,7 +147,6 @@ struct audio_player { char *data[1]; // data pointers for current output, planar or not, may point to 'buffer' int nsamples; // nsamples remaining for output - }; int audio_mixer_adjust(struct audio_player *ap, int delta); @@ -583,12 +583,39 @@ int audio_init_media(struct audio_player *ap, const char *path) { return -1; } +int audio_checkpoint_state(struct audio_player *ap) { + dbtxn *tx = dbindex_begin(ap->index, NULL, 0); + + if (tx) { + // TODO: meaningful state value + if (ap->playing) { + ap->playing_state.state = 1; + ap->playing_state.fileid = ap->playing->id; + } else { + ap->playing_state.state = 0; + ap->playing_state.fileid = 0; + } + printf("checkpoint state=%d file=%d '%s'\n", ap->playing_state.state, ap->playing_state.fileid, ap->playing_path); + // ap->pos? + ap->playing_state.pos = 0; + ap->playing_state.stamp = time(NULL); + if (dbstate_put(tx, ap->index, &ap->playing_state) == 0) { + dbindex_commit(tx); + } else { + dbindex_abort(tx); + } + } + + return 0; +} + // Next in play queue int audio_next_file(struct audio_player *ap) { int res; int empty = ap->playing == NULL; audio_close_media(ap); + do { //res = dbfile_next(ap->index, &ap->playing, &ap->playing_path); printf("a ap playing = %d\n", ap->playing ? ap->playing->id : -1); @@ -601,6 +628,8 @@ int audio_next_file(struct audio_player *ap) { res = 1; } while (res != 0 && res !=(-30798)); // MDB_NOTFOUND + audio_checkpoint_state(ap); + //if (res != 0) { // audio_stop_pcm(ap); //} @@ -622,6 +651,8 @@ int audio_prev_file(struct audio_player *ap) { res = 1; } while (res != 0 && res !=(-30798)); // MDB_NOTFOUND + audio_checkpoint_state(ap); + //if (res != 0) { // audio_stop_pcm(ap); //} @@ -629,6 +660,45 @@ int audio_prev_file(struct audio_player *ap) { return res; } +// first file on restarting server, see if we were playing something last time and start back there +// TODO: do something with the position +int audio_restore_state(struct audio_player *ap) { + dbtxn *tx = dbindex_begin(ap->index, NULL, 1); + int res = -1; + + if (dbstate_get(tx, ap->index, &ap->playing_state) == 0 && ap->playing_state.state == 1) { + dbfile *file = dbfile_get(tx, ap->index, ap->playing_state.fileid); + + if (file) { + dbdisk *disk = dbdisk_get(tx, ap->index, file->diskid); + + if (disk) { + char path[strlen(disk->mount) + strlen(file->path) + 1]; + + sprintf(path, "%s%s", disk->mount, file->path); + ap->playing = file; + ap->playing_path = strdup(path); + + dbdisk_free(disk); + + res = audio_init_media(ap, ap->playing_path); + } else { + dbfile_free(file); + } + } + } + + dbindex_commit(tx); + + printf("restore state=%d file=%d '%s'\n", ap->playing_state.state, ap->playing_state.fileid, ap->playing_path); + + if (res == 0) + return res; + + return audio_next_file(ap); +} + + void audio_player_control(struct audio_player *ap) { int ready = notify_msg_ready(ap->player); @@ -845,7 +915,7 @@ void audio_player_loop(struct audio_player *ap) { AVFrame *frame = av_frame_alloc(); AVFrame *oframe = av_frame_alloc(); - audio_next_file(ap); + audio_restore_state(ap); while (1) { int res; -- 2.39.5