diff --git a/src/SMARTPL2SQL.g b/src/SMARTPL2SQL.g index 43f3f894..d1ad199d 100644 --- a/src/SMARTPL2SQL.g +++ b/src/SMARTPL2SQL.g @@ -187,7 +187,7 @@ expression returns [ pANTLR3_STRING result ] } else if (strcmp((char *)val, "url") == 0) { - sprintf(str, "f.data_kind = \%d", DATA_KIND_URL); + sprintf(str, "f.data_kind = \%d", DATA_KIND_HTTP); } else if (strcmp((char *)val, "spotify") == 0) { diff --git a/src/db.c b/src/db.c index b4cdfdb1..ca94fe8c 100644 --- a/src/db.c +++ b/src/db.c @@ -2050,7 +2050,7 @@ db_files_update_songalbumid(void) void db_file_inc_playcount(int id) { -#define Q_TMPL "UPDATE files SET play_count = play_count + 1, time_played = %" PRIi64 " WHERE id = %d;" +#define Q_TMPL "UPDATE files SET play_count = play_count + 1, time_played = %" PRIi64 ", seek = 0 WHERE id = %d;" char *query; query = sqlite3_mprintf(Q_TMPL, (int64_t)time(NULL), id); @@ -2754,6 +2754,27 @@ db_file_update_icy(int id, char *artist, char *album) #undef Q_TMPL } +void +db_file_save_seek(int id, uint32_t seek) +{ +#define Q_TMPL "UPDATE files SET seek = %d WHERE id = %d;" + char *query; + + if (id == 0) + return; + + query = sqlite3_mprintf(Q_TMPL, seek, id); + if (!query) + { + DPRINTF(E_LOG, L_DB, "Out of memory for query string\n"); + + return; + } + + db_query_run(query, 1, 0); +#undef Q_TMPL +} + void db_file_delete_bypath(char *path) { diff --git a/src/db.h b/src/db.h index e5f5c660..d5ac0fa7 100644 --- a/src/db.h +++ b/src/db.h @@ -104,7 +104,7 @@ enum media_kind { enum data_kind { DATA_KIND_FILE = 0, /* normal file */ - DATA_KIND_URL = 1, /* url/stream */ + DATA_KIND_HTTP = 1, /* network stream (radio) */ DATA_KIND_SPOTIFY = 2, /* iTunes has no spotify data kind, but we use 2 */ DATA_KIND_PIPE = 3, /* iTunes has no pipe data kind, but we use 3 */ }; @@ -473,6 +473,9 @@ db_file_update(struct media_file_info *mfi); void db_file_update_icy(int id, char *artist, char *album); +void +db_file_save_seek(int id, uint32_t seek); + void db_file_delete_bypath(char *path); diff --git a/src/filescanner.c b/src/filescanner.c index d06c5468..39a47db4 100644 --- a/src/filescanner.c +++ b/src/filescanner.c @@ -706,7 +706,7 @@ filescanner_process_media(char *path, time_t mtime, off_t size, int type, struct } else if (type & F_SCAN_TYPE_URL) { - mfi->data_kind = DATA_KIND_URL; + mfi->data_kind = DATA_KIND_HTTP; ret = scan_metadata_ffmpeg(path, mfi); if (ret < 0) { diff --git a/src/filescanner_ffmpeg.c b/src/filescanner_ffmpeg.c index 4fd6d785..aeefecf3 100644 --- a/src/filescanner_ffmpeg.c +++ b/src/filescanner_ffmpeg.c @@ -335,14 +335,14 @@ scan_metadata_ffmpeg(char *file, struct media_file_info *mfi) #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 3) # ifndef HAVE_FFMPEG // Without this, libav is slow to probe some internet streams - if (mfi->data_kind == DATA_KIND_URL) + if (mfi->data_kind == DATA_KIND_HTTP) { ctx = avformat_alloc_context(); ctx->probesize = 64000; } # endif - if (mfi->data_kind == DATA_KIND_URL) + if (mfi->data_kind == DATA_KIND_HTTP) { free(path); ret = http_stream_setup(&path, file); @@ -481,8 +481,8 @@ scan_metadata_ffmpeg(char *file, struct media_file_info *mfi) DPRINTF(E_DBG, L_SCAN, "Duration %d ms, bitrate %d kbps\n", mfi->song_length, mfi->bitrate); - /* Try to extract ICY metadata if url/stream */ - if (mfi->data_kind == DATA_KIND_URL) + /* Try to extract ICY metadata if http stream */ + if (mfi->data_kind == DATA_KIND_HTTP) { icy_metadata = http_icy_metadata_get(ctx, 0); if (icy_metadata && icy_metadata->name) diff --git a/src/httpd_dacp.c b/src/httpd_dacp.c index 8e1bb366..b0f3a93a 100644 --- a/src/httpd_dacp.c +++ b/src/httpd_dacp.c @@ -170,7 +170,7 @@ dacp_nowplaying(struct evbuffer *evbuf, struct player_status *status, struct med * FIXME: Giving the client invalid ids on purpose is hardly ideal, but the * clients don't seem to use these ids for anything other than rating. */ - if (mfi->data_kind == DATA_KIND_URL) + if (mfi->data_kind == DATA_KIND_HTTP) { id = djb_hash(mfi->album, strlen(mfi->album)); songalbumid = (int64_t)id; diff --git a/src/lastfm.c b/src/lastfm.c index 089c4e03..11dddf2d 100644 --- a/src/lastfm.c +++ b/src/lastfm.c @@ -491,7 +491,7 @@ scrobble(int id) goto noscrobble; // Don't scrobble non-music and radio stations - if ((mfi->media_kind != MEDIA_KIND_MUSIC) || (mfi->data_kind == DATA_KIND_URL)) + if ((mfi->media_kind != MEDIA_KIND_MUSIC) || (mfi->data_kind == DATA_KIND_HTTP)) goto noscrobble; // Don't scrobble songs with unknown artist diff --git a/src/pipe.c b/src/pipe.c index c8c9660d..76bc672d 100644 --- a/src/pipe.c +++ b/src/pipe.c @@ -81,7 +81,7 @@ pipe_setup(struct media_file_info *mfi) return -1; } - return 1; + return 0; } void diff --git a/src/player.c b/src/player.c index 1db11f83..611314d5 100644 --- a/src/player.c +++ b/src/player.c @@ -1173,21 +1173,21 @@ player_queue_make_mpd(char *path, int recursive) static void source_free(struct player_source *ps) { - switch (ps->type) + switch (ps->data_kind) { - case SOURCE_FILE: - case SOURCE_HTTP: + case DATA_KIND_FILE: + case DATA_KIND_HTTP: if (ps->ctx) transcode_cleanup(ps->ctx); break; - case SOURCE_SPOTIFY: + case DATA_KIND_SPOTIFY: #ifdef HAVE_SPOTIFY_H spotify_playback_stop(); #endif break; - case SOURCE_PIPE: + case DATA_KIND_PIPE: pipe_cleanup(); break; } @@ -1202,10 +1202,10 @@ source_stop(struct player_source *ps) while (ps) { - switch (ps->type) + switch (ps->data_kind) { - case SOURCE_FILE: - case SOURCE_HTTP: + case DATA_KIND_FILE: + case DATA_KIND_HTTP: if (ps->ctx) { transcode_cleanup(ps->ctx); @@ -1213,13 +1213,13 @@ source_stop(struct player_source *ps) } break; - case SOURCE_SPOTIFY: + case DATA_KIND_SPOTIFY: #ifdef HAVE_SPOTIFY_H spotify_playback_stop(); #endif break; - case SOURCE_PIPE: + case DATA_KIND_PIPE: pipe_cleanup(); break; } @@ -1360,7 +1360,7 @@ source_reshuffle(void) /* Helper */ static int -source_open(struct player_source *ps, int no_md) +source_open(struct player_source *ps, int no_md, int seek) { struct media_file_info *mfi; char *url; @@ -1390,12 +1390,13 @@ source_open(struct player_source *ps, int no_md) DPRINTF(E_INFO, L_PLAYER, "Opening '%s' (%s)\n", mfi->title, mfi->path); + ps->data_kind = mfi->data_kind; + ps->media_kind = mfi->media_kind; + // Setup the source type responsible for getting the audio switch (mfi->data_kind) { - case DATA_KIND_URL: - ps->type = SOURCE_HTTP; - + case DATA_KIND_HTTP: ret = http_stream_setup(&url, mfi->path); if (ret < 0) break; @@ -1407,22 +1408,29 @@ source_open(struct player_source *ps, int no_md) break; case DATA_KIND_SPOTIFY: - ps->type = SOURCE_SPOTIFY; #ifdef HAVE_SPOTIFY_H ret = spotify_playback_play(mfi); + if (seek && mfi->seek) + { + DPRINTF(E_DBG, L_PLAYER, "Source id %d started with seek %d\n", ps->id, mfi->seek); + ret = spotify_playback_seek(mfi->seek); + } #else ret = -1; #endif break; case DATA_KIND_PIPE: - ps->type = SOURCE_PIPE; ret = pipe_setup(mfi); break; default: - ps->type = SOURCE_FILE; ret = transcode_setup(&ps->ctx, mfi, NULL, 0); + if (seek && mfi->seek) + { + DPRINTF(E_DBG, L_PLAYER, "Source id %d started with seek %d\n", ps->id, mfi->seek); + ret = transcode_seek(ps->ctx, mfi->seek); + } } free_mfi(mfi, 0); @@ -1439,7 +1447,7 @@ source_open(struct player_source *ps, int no_md) ps->setup_done = 1; - return 0; + return ret; } static int @@ -1479,7 +1487,7 @@ source_next(int force) if (!cur_streaming) break; - if ((cur_streaming->type == SOURCE_FILE) && cur_streaming->ctx) + if ((cur_streaming->data_kind == DATA_KIND_FILE) && cur_streaming->ctx) { ret = transcode_seek(cur_streaming->ctx, 0); @@ -1491,7 +1499,7 @@ source_next(int force) metadata_trigger(cur_streaming, 0); } else - ret = source_open(cur_streaming, force); + ret = source_open(cur_streaming, force, 0); if (ret < 0) { @@ -1535,7 +1543,7 @@ source_next(int force) do { - ret = source_open(ps, force); + ret = source_open(ps, force, 0); if (ret < 0) { if (shuffle) @@ -1593,7 +1601,7 @@ source_prev(void) do { - ret = source_open(ps, 1); + ret = source_open(ps, 1, 0); if (ret < 0) { if (shuffle) @@ -1741,7 +1749,7 @@ source_check(void) if (ps->setup_done) { - if ((ps->type == SOURCE_FILE) && ps->ctx) + if ((ps->data_kind == DATA_KIND_FILE) && ps->ctx) { transcode_cleanup(ps->ctx); ps->ctx = NULL; @@ -1796,7 +1804,7 @@ source_check(void) if (ps->setup_done) { - if ((ps->type == SOURCE_FILE) && ps->ctx) + if ((ps->data_kind == DATA_KIND_FILE) && ps->ctx) { transcode_cleanup(ps->ctx); ps->ctx = NULL; @@ -1882,26 +1890,26 @@ source_read(uint8_t *buf, int len, uint64_t rtptime) if (evbuffer_get_length(audio_buf) == 0) { - switch (cur_streaming->type) + switch (cur_streaming->data_kind) { - case SOURCE_HTTP: + case DATA_KIND_HTTP: ret = transcode(cur_streaming->ctx, audio_buf, len - nbytes, &icy_timer); if (icy_timer) metadata_check_icy(); break; - case SOURCE_FILE: + case DATA_KIND_FILE: ret = transcode(cur_streaming->ctx, audio_buf, len - nbytes, &icy_timer); break; #ifdef HAVE_SPOTIFY_H - case SOURCE_SPOTIFY: + case DATA_KIND_SPOTIFY: ret = spotify_audio_get(audio_buf, len - nbytes); break; #endif - case SOURCE_PIPE: + case DATA_KIND_PIPE: ret = pipe_audio_get(audio_buf, len - nbytes); break; @@ -2647,7 +2655,7 @@ artwork_url_get(struct player_command *cmd) return -1; /* Check that we are playing a viable stream, and that it has the requested id */ - if (!ps->ctx || ps->type != SOURCE_HTTP || ps->id != cmd->arg.icy.id) + if (!ps->ctx || ps->data_kind != DATA_KIND_HTTP || ps->id != cmd->arg.icy.id) return -1; transcode_metadata_artwork_url(ps->ctx, &cmd->arg.icy.artwork_url); @@ -2874,7 +2882,7 @@ playback_start(struct player_command *cmd) else cur_streaming = ps; - ret = source_open(cur_streaming, 0); + ret = source_open(cur_streaming, 0, 1); if (ret < 0) { DPRINTF(E_LOG, L_PLAYER, "Couldn't jump to source %d in queue\n", cur_streaming->id); @@ -2886,7 +2894,7 @@ playback_start(struct player_command *cmd) if (idx_id) *idx_id = cur_streaming->id; - cur_streaming->stream_start = last_rtptime + AIRTUNES_V2_PACKET_SAMPLES; + cur_streaming->stream_start = last_rtptime + AIRTUNES_V2_PACKET_SAMPLES - ((uint64_t)ret * 44100) / 1000; cur_streaming->output_start = cur_streaming->stream_start; } else if (!cur_streaming) @@ -3023,7 +3031,7 @@ playback_prev_bh(struct player_command *cmd) } else { - ret = source_open(cur_streaming, 1); + ret = source_open(cur_streaming, 1, 0); if (ret < 0) { playback_abort(); @@ -3103,18 +3111,18 @@ playback_seek_bh(struct player_command *cmd) ps->end = 0; /* Seek to commanded position */ - switch (ps->type) + switch (ps->data_kind) { - case SOURCE_FILE: + case DATA_KIND_FILE: ret = transcode_seek(ps->ctx, ms); break; #ifdef HAVE_SPOTIFY_H - case SOURCE_SPOTIFY: + case DATA_KIND_SPOTIFY: ret = spotify_playback_seek(ms); break; #endif - case SOURCE_PIPE: - case SOURCE_HTTP: + case DATA_KIND_PIPE: + case DATA_KIND_HTTP: ret = 1; break; @@ -3162,13 +3170,13 @@ playback_pause_bh(struct player_command *cmd) pos -= ps->stream_start; ms = (int)((pos * 1000) / 44100); - switch (ps->type) + switch (ps->data_kind) { - case SOURCE_FILE: + case DATA_KIND_FILE: ret = transcode_seek(ps->ctx, ms); break; #ifdef HAVE_SPOTIFY_H - case SOURCE_SPOTIFY: + case DATA_KIND_SPOTIFY: ret = spotify_playback_seek(ms); break; #endif @@ -3192,6 +3200,9 @@ playback_pause_bh(struct player_command *cmd) status_update(PLAY_PAUSED); + if (ps->media_kind & (MEDIA_KIND_MOVIE | MEDIA_KIND_PODCAST | MEDIA_KIND_AUDIOBOOK | MEDIA_KIND_TVSHOW)) + db_file_save_seek(ps->id, ret); + return 0; } diff --git a/src/player.h b/src/player.h index eb127484..ac9842e4 100644 --- a/src/player.h +++ b/src/player.h @@ -33,13 +33,6 @@ enum repeat_mode { REPEAT_ALL = 2, }; -enum source_type { - SOURCE_FILE = 0, - SOURCE_SPOTIFY, - SOURCE_PIPE, - SOURCE_HTTP, -}; - struct spk_flags { unsigned selected:1; unsigned has_password:1; @@ -84,7 +77,8 @@ struct player_source uint32_t id; uint32_t len_ms; - enum source_type type; + enum data_kind data_kind; + enum media_kind media_kind; int setup_done; uint64_t stream_start; diff --git a/src/transcode.c b/src/transcode.c index f07f31f3..3b2e076d 100644 --- a/src/transcode.c +++ b/src/transcode.c @@ -507,13 +507,13 @@ transcode_setup(struct transcode_ctx **nctx, struct media_file_info *mfi, off_t #if LIBAVFORMAT_VERSION_MAJOR >= 54 || (LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR >= 3) # ifndef HAVE_FFMPEG // Without this, libav is slow to probe some internet streams, which leads to RAOP timeouts - if (mfi->data_kind == DATA_KIND_URL) + if (mfi->data_kind == DATA_KIND_HTTP) { ctx->fmtctx = avformat_alloc_context(); ctx->fmtctx->probesize = 64000; } # endif - if (mfi->data_kind == DATA_KIND_URL) + if (mfi->data_kind == DATA_KIND_HTTP) av_dict_set(&options, "icy", "1", 0); ret = avformat_open_input(&ctx->fmtctx, mfi->path, NULL, &options);