From 626f299dd3512d44df4bcf95fc7a21b9417c06b0 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Tue, 22 Oct 2024 18:11:37 -0400 Subject: Various fixes, doc cleanup Signed-off-by: Andrew Opalach --- .gitignore | 2 +- doc/database.txt | 45 ------ doc/design.dia | 224 +++++++++++++++++----------- doc/design.txt | 15 +- doc/design_diagram.svg | 43 +++--- doc/network_independent_audio_pause.kra | Bin 1129580 -> 1332660 bytes doc/network_independent_audio_pause.png | Bin 213662 -> 148138 bytes doc/pal_vs_ntsc_aspect_ratio.png | Bin 72101 -> 0 bytes doc/references.txt | 64 -------- doc/references/pal_vs_ntsc_aspect_ratio.png | Bin 0 -> 72101 bytes doc/references/references.txt | 64 ++++++++ doc/style.css | 4 +- flake.lock | 6 +- flake.nix | 2 + meson.build | 2 +- src/buffer/clock.c | 1 - src/buffer/video.c | 5 +- src/cache/meson.build | 19 ++- src/codec/ffmpeg/decoder.c | 2 + src/liana/client.c | 22 ++- src/liana/client.h | 3 +- src/liana/handler.h | 4 +- src/liana/handlers/cdio_server.c | 1 - src/liana/list.c | 4 +- src/liana/list.h | 23 +-- src/liana/meson.build | 13 +- src/liana/vcr.c | 6 +- src/libsink/common.h | 2 +- src/libsink/sink.c | 26 ++-- src/libsink/sink.h | 1 + src/server/local_compat.c | 10 +- src/sink/desktop.c | 1 + 32 files changed, 328 insertions(+), 286 deletions(-) delete mode 100644 doc/database.txt delete mode 100644 doc/pal_vs_ntsc_aspect_ratio.png delete mode 100644 doc/references.txt create mode 100644 doc/references/pal_vs_ntsc_aspect_ratio.png create mode 100644 doc/references/references.txt diff --git a/.gitignore b/.gitignore index 025cabc..443f273 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,7 @@ build*/ compile_commands.json data/ -doc/**.html +doc/**/*.html env/bin/ old*/ src/portal/cpy/portal.c diff --git a/doc/database.txt b/doc/database.txt deleted file mode 100644 index 0d2afa2..0000000 --- a/doc/database.txt +++ /dev/null @@ -1,45 +0,0 @@ -= CAMU Database (Archive) - -Types of Media for Consideration --------------------------------- -- Music - - Singles - - Albums - - Music Videos - - Playlists (Single/Split file(s)) - - Video Game OST (ripped) - - CD - -- Video - - Movies/TV Shows - - Youtube Channels/Videos - - DVD/Blu-ray - -- Art - - Artists - - Twitter/Pixiv Profiles - -- Games - - Steam Games - - Roms - - Achievements - - Time Tracking - -Database --------- -* Tied to a single directory on the filesystem -* index.json -* Easily referenced external files. -** external: - -Database-specific Types ------------------------ -Collection -~~~~~~~~~~ -A defined set of resources that may be stored either too loose or too bundled than desired. The exact parameters that qualify a set of resources to become a collection is up to the database owner. A general rule of thumb should be that the relationship of the resources in a collection should be externally defined and commonly agreed upon. You may also want to consider if that relationship is "official" or legally defined, whatever that would mean for your case. -Examples -^^^^^^^^ -* A music album where each file is a track. -* An art book part of a larger zip archive with multiple other resources/collections. - -// vim: set syntax=asciidoc: diff --git a/doc/design.dia b/doc/design.dia index cd3c41b..e78aeca 100644 --- a/doc/design.dia +++ b/doc/design.dia @@ -94,6 +94,8 @@ + + @@ -212,52 +214,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -302,7 +259,7 @@ - + @@ -347,7 +304,7 @@ - + @@ -380,7 +337,7 @@ - + @@ -425,7 +382,7 @@ - + @@ -440,7 +397,7 @@ - + @@ -464,7 +421,7 @@ - + @@ -497,26 +454,26 @@ - + - + - + - #Tree (server)# + #Server# - + - + @@ -530,7 +487,7 @@ - + @@ -557,7 +514,7 @@ - + @@ -602,7 +559,7 @@ - + @@ -647,7 +604,7 @@ - + @@ -692,7 +649,7 @@ - + @@ -710,16 +667,16 @@ - + - + - + - - + + @@ -746,7 +703,7 @@ - + @@ -779,7 +736,7 @@ - + @@ -824,7 +781,7 @@ - + @@ -842,7 +799,7 @@ - + @@ -860,7 +817,7 @@ - + @@ -878,12 +835,12 @@ - + - + - + @@ -897,7 +854,7 @@ - + @@ -914,17 +871,17 @@ - + - + - + - #BIMU™ (ビム) Stream# + #Synced Stream (liana)# @@ -933,7 +890,7 @@ - + @@ -950,7 +907,7 @@ - + @@ -983,7 +940,7 @@ - + @@ -1016,5 +973,104 @@ + + + + + + + + + + + ## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #The Internet# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #You# + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/design.txt b/doc/design.txt index 95d8b48..ef98961 100644 --- a/doc/design.txt +++ b/doc/design.txt @@ -8,8 +8,7 @@ Breif on Components ------------------- Server ~~~~~~ -The "server" is the main hub responsible for all handling user account related functions and state, as well -as managing the network of all other individual components. +The server is the main hub responsible for all handling user account related functions and state, as well as managing the network of all other individual components. User Accounts ^^^^^^^^^^^^^ @@ -25,15 +24,15 @@ Users accounts contain 4 main concepts: lists, media lists, history, and setting Node ~~~~ -Nodes can be seen as distributed resource managers for the server. They each contain up to 3 main parts: A source manager and/or database, and a resource host. A node can have one or both of a source manager and database but a node without either is useless. +Nodes can be seen as distributed resource managers for the server. They each contain up to 3 main parts: A source manager and/or database, then a resource host. A node can have one or both of a source manager and database but a node without either is useless. Source Manager ^^^^^^^^^^^^^^ -A source manager implements any or all of browsing, searching, and custom resource actions. A big point of a source manager is to be able to work entirely behind a proxy. Some examples of sources include a social media website, filesystem directory, dvd drive, or radio antenna. An example of browsing could be apple music's "New Music". An example of searching, youtube search. A custom action could be liking a post on twitter. +A source manager implements any or all of browsing, searching, and custom resource actions. A big point of a source manager is to be able to work entirely behind a proxy. Some examples of sources may include a social media website, filesystem directory, dvd drive, or radio antenna. An example of browsing could be apple music's "New Music". An example of searching, youtube search. A custom action could be liking a post on twitter. Database ^^^^^^^^ -Stores resources locally along with as much metadata as possible. Simply used to retrive resources locally instead of going through the source manager. +Stores resources along with as much metadata as possible. Simply used to retrive resources locally instead of going through the source manager. Resource Host ^^^^^^^^^^^^^ @@ -41,7 +40,7 @@ Hosts node-local resources for the server to use for streaming. Should support a Client ~~~~~~ -Clients are only way a user interacts with the reset of the network besides the special case of play/pause/seek which can also be done from a sink. +Clients are the only way a user interacts with the rest of the network besides the special case of play, pause, skip and seek which can be done from a sink. libclient ^^^^^^^^^ @@ -49,10 +48,10 @@ C library that integrates with the rest of the code-base to abstract communicati Sink ~~~~ -A sink's only purpose is to be a minimal yet optimal way to view the entries in a list. +A sink's only purpose is to be a minimal, yet optimal, way to view the entries in a list. libsink ^^^^^^^ -C library that abstracts communicating with the server as a sink in a platform- and environment-independent way. It makes no assumptions about what kind of device (physical or otherwise) it's running on or outputting to. +C library that abstracts communicating with the server as a sink in a platform- and environment-independent way. // vim: set syntax=asciidoc: diff --git a/doc/design_diagram.svg b/doc/design_diagram.svg index 1c2ed04..693b086 100644 --- a/doc/design_diagram.svg +++ b/doc/design_diagram.svg @@ -1,6 +1,8 @@ - + + + @@ -81,12 +83,6 @@ - - - - - - @@ -387,15 +383,15 @@ - - - + + + Sink (libsink) - - Tree (server) + + Server @@ -466,9 +462,9 @@ - - - + + + Node @@ -487,11 +483,11 @@ - - Remote Resource + + Remote Resource - - BIMU™ (ビム) Stream + + Synced Stream (liana) @@ -499,5 +495,14 @@ System Interface + + + + + The Internet + + + You + diff --git a/doc/network_independent_audio_pause.kra b/doc/network_independent_audio_pause.kra index c0e39de..91b391e 100644 Binary files a/doc/network_independent_audio_pause.kra and b/doc/network_independent_audio_pause.kra differ diff --git a/doc/network_independent_audio_pause.png b/doc/network_independent_audio_pause.png index b5aa516..8e696e2 100644 Binary files a/doc/network_independent_audio_pause.png and b/doc/network_independent_audio_pause.png differ diff --git a/doc/pal_vs_ntsc_aspect_ratio.png b/doc/pal_vs_ntsc_aspect_ratio.png deleted file mode 100644 index e570f70..0000000 Binary files a/doc/pal_vs_ntsc_aspect_ratio.png and /dev/null differ diff --git a/doc/references.txt b/doc/references.txt deleted file mode 100644 index 702f7eb..0000000 --- a/doc/references.txt +++ /dev/null @@ -1,64 +0,0 @@ -:stylesheet: style.css - -= References - -Video ------ -Vsync/VRR -~~~~~~~~~ -* https://github.com/swaywm/sway/issues/5076 -* https://en.wikipedia.org/wiki/Motion_interpolation -* https://gamedev.stackexchange.com/questions/82318/what-problem-does-double-or-triple-buffering-solve-in-modern-games - - Good explanation of vsync and multiple buffering -* https://linustechtips.com/topic/1508075-no-vsync-with-no-screen-tearing-possible/?do=findComment&comment=15948456 -* https://forums.tomshardware.com/threads/games-screen-tearing-without-vsync.3272775/post-20062033 -* Current understanding of vsync and tearing: - - Vsync operates on an interupt. - - You cannot avoid tearing without vsync. - - VRR is completely ineffective outside of the display's supported range. - - A higher fps and refresh rate while tearing will be less noticable. -* https://blurbusters.com/gsync/gsync101-input-lag-tests-and-settings/14/ -* https://blurbusters.com/gsync/gsync101-input-lag-tests-and-settings/15/ -* https://old.reddit.com/r/Amd/comments/4ypw5k/freesync_is_so_fcking_awesome/d6zl13v/ - -Latency/Present -~~~~~~~~~~~~~~~ -* https://themaister.net/blog/2023/11/12/my-scuffed-game-streaming-adventure-pyrofling/ - -Old Video Standards Stuff -~~~~~~~~~~~~~~~~~~~~~~~~~ -* https://en.wikipedia.org/wiki/24p -* https://en.wikipedia.org/wiki/Three-two_pull_down -* https://cinematography.com/index.php?/forums/topic/71346-why-23976-and-not-24-fps/&tab=comments#comment-455454 -* https://forum.doom9.org/archive/index.php/t-163655.html -* https://en.wikipedia.org/wiki/pixel_aspect_ratio -* https://en.wikipedia.org/wiki/display_aspect_ratio - - PAL and NTSC are both supposed to be displayed on 4:3 physical aspect ratio screens even though they are internally different aspect ratios and resolutions. The difference is the size of the "pixel" (PAL has more, shorter scanlines). - image:pal_vs_ntsc_aspect_ratio.png[PalVsNtsc,1100] -* https://en.wikipedia.org/wiki/Anamorphic_widescreen - -Python ------- -* https://stackoverflow.com/questions/38243682/whats-the-standard-way-to-package-a-python-project-with-dependencies - -Audio ------ -Formats -~~~~~~~ -* https://github.com/derselbst/ANMP -* https://slack.net/~ant/libs/audio.html#Game_Music_Emu - -Drivers -~~~~~~~ -* https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/master/spa/plugins/alsa/test-timer.c -* https://stackoverflow.com/questions/41263580/what-exactly-does-alsas-snd-pcm-delay-return -* https://stackoverflow.com/questions/24040672/the-meaning-of-period-in-alsa - -Interface ---------- -Terminal -~~~~~~~~ -* https://www.amp-what.com/ -* https://www.unicode.org/charts/beta/nameslist/n_2B00.html - -// vim: set syntax=asciidoc: diff --git a/doc/references/pal_vs_ntsc_aspect_ratio.png b/doc/references/pal_vs_ntsc_aspect_ratio.png new file mode 100644 index 0000000..e570f70 Binary files /dev/null and b/doc/references/pal_vs_ntsc_aspect_ratio.png differ diff --git a/doc/references/references.txt b/doc/references/references.txt new file mode 100644 index 0000000..fafba93 --- /dev/null +++ b/doc/references/references.txt @@ -0,0 +1,64 @@ +:stylesheet: ../style.css + += References + +Video +----- +Vsync/VRR +~~~~~~~~~ +* https://github.com/swaywm/sway/issues/5076 +* https://en.wikipedia.org/wiki/Motion_interpolation +* https://gamedev.stackexchange.com/questions/82318/what-problem-does-double-or-triple-buffering-solve-in-modern-games + - Good explanation of vsync and multiple buffering +* https://linustechtips.com/topic/1508075-no-vsync-with-no-screen-tearing-possible/?do=findComment&comment=15948456 +* https://forums.tomshardware.com/threads/games-screen-tearing-without-vsync.3272775/post-20062033 +* Current understanding of vsync and tearing: + - Vsync operates on an interupt. + - You cannot avoid tearing without vsync. + - VRR is completely ineffective outside of the display's supported range. + - A higher fps and refresh rate while tearing will be less noticable. +* https://blurbusters.com/gsync/gsync101-input-lag-tests-and-settings/14/ +* https://blurbusters.com/gsync/gsync101-input-lag-tests-and-settings/15/ +* https://old.reddit.com/r/Amd/comments/4ypw5k/freesync_is_so_fcking_awesome/d6zl13v/ + +Latency/Present +~~~~~~~~~~~~~~~ +* https://themaister.net/blog/2023/11/12/my-scuffed-game-streaming-adventure-pyrofling/ + +Old Video Standards Stuff +~~~~~~~~~~~~~~~~~~~~~~~~~ +* https://en.wikipedia.org/wiki/24p +* https://en.wikipedia.org/wiki/Three-two_pull_down +* https://cinematography.com/index.php?/forums/topic/71346-why-23976-and-not-24-fps/&tab=comments#comment-455454 +* https://forum.doom9.org/archive/index.php/t-163655.html +* https://en.wikipedia.org/wiki/pixel_aspect_ratio +* https://en.wikipedia.org/wiki/display_aspect_ratio + - PAL and NTSC are both supposed to be displayed on 4:3 physical aspect ratio screens even though they are internally different aspect ratios and resolutions. The difference is the size of the "pixel" (PAL has more, shorter scanlines). + image:pal_vs_ntsc_aspect_ratio.png[PalVsNtsc,1100] +* https://en.wikipedia.org/wiki/Anamorphic_widescreen + +Python +------ +* https://stackoverflow.com/questions/38243682/whats-the-standard-way-to-package-a-python-project-with-dependencies + +Audio +----- +Formats +~~~~~~~ +* https://github.com/derselbst/ANMP +* https://slack.net/~ant/libs/audio.html#Game_Music_Emu + +Drivers +~~~~~~~ +* https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/master/spa/plugins/alsa/test-timer.c +* https://stackoverflow.com/questions/41263580/what-exactly-does-alsas-snd-pcm-delay-return +* https://stackoverflow.com/questions/24040672/the-meaning-of-period-in-alsa + +Interface +--------- +Terminal +~~~~~~~~ +* https://www.amp-what.com/ +* https://www.unicode.org/charts/beta/nameslist/n_2B00.html + +// vim: set syntax=asciidoc: diff --git a/doc/style.css b/doc/style.css index bc6ed15..e52223b 100644 --- a/doc/style.css +++ b/doc/style.css @@ -1,7 +1,7 @@ body { font-family: serif; margin: 1em 45% 1em 5%; - background-color: #f4ddca + background-color: #fef9fa; } h3 { @@ -9,5 +9,5 @@ h3 { } strong { - color: #543e41; + color: #423152; } diff --git a/flake.lock b/flake.lock index df7f46a..36ef2ff 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1729256560, - "narHash": "sha256-/uilDXvCIEs3C9l73JTACm4quuHUsIHcns1c+cHUJwA=", + "lastModified": 1729413321, + "narHash": "sha256-I4tuhRpZFa6Fu6dcH9Dlo5LlH17peT79vx1y1SpeKt0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "4c2fcb090b1f3e5b47eaa7bd33913b574a11e0a0", + "rev": "1997e4aa514312c1af7e2bda7fad1644e778ff26", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index bf8bf4f..2faaf91 100644 --- a/flake.nix +++ b/flake.nix @@ -154,6 +154,8 @@ buildInputs = with pkgsCross.ucrt64; [ (zlib.override { shared = false; static = true; }) xxHash + openssl + libidn2 ]; shellHook = '' export NIX_SHELL="camu-mingw64" diff --git a/meson.build b/meson.build index abf383b..c088ff4 100644 --- a/meson.build +++ b/meson.build @@ -41,7 +41,7 @@ endif if get_option('server').enabled() subdir('src/server') if not meson.is_subproject() - subdir('src/fruits/cmsrv') + subdir('src/fruits/cmsrv') endif endif diff --git a/src/buffer/clock.c b/src/buffer/clock.c index c4a07a6..a04bb08 100644 --- a/src/buffer/clock.c +++ b/src/buffer/clock.c @@ -59,7 +59,6 @@ void camu_clock_resume(struct camu_clock *clock, u64 target) //} else if (target > 0) { if (target > 0) { tick = calc_tick_offset(tick, aki_get_timestamp(), target); - al_printf("%f\n", tick); } if (clock->paused_at == 0.0) { if (target == 0) { diff --git a/src/buffer/video.c b/src/buffer/video.c index b2381b2..a7a5594 100644 --- a/src/buffer/video.c +++ b/src/buffer/video.c @@ -149,6 +149,7 @@ void camu_video_buffer_push(struct camu_video_buffer *buf, struct camu_codec_fra // Not thread-safe, must be called while the buffer is not being read from or written to. void camu_video_buffer_reset(struct camu_video_buffer *buf) { + buf->pts = -1.0; buf->queue->reset(buf->queue); buf->buffered = false; al_atomic_store(u8)(&buf->flow, FLOWING, AL_ATOMIC_RELAXED); @@ -172,7 +173,7 @@ bool camu_video_buffer_read(struct camu_video_buffer *buf, void *out) f64 pts = camu_clock_get_pts(buf->clock, buf->latency); if (pts > buf->pts) buf->pts = pts; } - u8 flow = al_atomic_load(u8)(&buf->flow, AL_ATOMIC_RELAXED); + u8 flow = al_atomic_load(u8)(&buf->flow, AL_ATOMIC_ACQUIRE); if (flow == SIGNALED && !buf->single_frame) { buf->callback(buf->userdata, CAMU_BUFFER_EOF); return false; @@ -180,7 +181,7 @@ bool camu_video_buffer_read(struct camu_video_buffer *buf, void *out) u8 ret = buf->queue->read(buf->queue, buf->pts, out); if (flow == FLUSHED && (ret == CAMU_QUEUE_EOF || (buf->single_frame && ret == CAMU_QUEUE_OK))) { buf->callback(buf->userdata, CAMU_BUFFER_EOF); - al_atomic_store(u8)(&buf->flow, SIGNALED, AL_ATOMIC_RELAXED); + al_atomic_store(u8)(&buf->flow, SIGNALED, AL_ATOMIC_RELEASE); al_log_debug("video_buffer", "Flushed."); } else if (flow == FLOWING && buf->queue->count(buf->queue) <= BUFFER_WATERMARK_LOW) { buf->callback(buf->userdata, CAMU_BUFFER_UNCORK); diff --git a/src/cache/meson.build b/src/cache/meson.build index 8684ccd..5fb47ae 100644 --- a/src/cache/meson.build +++ b/src/cache/meson.build @@ -3,9 +3,24 @@ cache_src = [ 'handle.c', 'threaded_waits.c', 'handlers/file.c', - 'handlers/cdio.c', 'backings/memory.c' ] +cache_deps = [] + +cache_have_cdio = false +libcdio_paranoia = dependency('libcdio_paranoia', required: false, allow_fallback: true) +libcdio_cdda = dependency('libcdio_cdda', required: false, allow_fallback: true) +if libcdio_paranoia.found() and libcdio_cdda.found() + cache_src += ['handlers/cdio.c'] + cache_deps += [libcdio_paranoia, libcdio_cdda] + cache_have_cdio = true +endif + +#libdvdcss = dependency('libdvdcss', required: false, allow_fallback: true) +#libdvdread = dependency('libdvdread', required: false, allow_fallback: true) +#libdvdnav = dependency('libdvdnav', required: false, allow_fallback: true) +#if libdvdcss.found() and libdvdread.found() and libdvdnav.found() +#endif if akiyo_has_mmap cache_src += ['backings/file_mapped.c'] @@ -17,4 +32,4 @@ if akiyo_has_curl cache_src += ['handlers/http.c'] endif -cache = declare_dependency(sources: cache_src) +cache = declare_dependency(sources: cache_src, dependencies: cache_deps) diff --git a/src/codec/ffmpeg/decoder.c b/src/codec/ffmpeg/decoder.c index d231b2f..3aafd35 100644 --- a/src/codec/ffmpeg/decoder.c +++ b/src/codec/ffmpeg/decoder.c @@ -14,6 +14,8 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend { struct camu_ff_decoder *av = (struct camu_ff_decoder *)dec; + av->codec_context = NULL; + AVCodecParameters *codecpar = stream->av.stream->codecpar; const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id); diff --git a/src/liana/client.c b/src/liana/client.c index d556453..5e33086 100644 --- a/src/liana/client.c +++ b/src/liana/client.c @@ -5,6 +5,7 @@ #include "client.h" #include "handlers.h" +#include "list.h" static void data_packet_callback(void *userdata, struct aki_packet_stream *stream, struct aki_packet *packet) { @@ -84,9 +85,17 @@ static void parse_info_packet(struct lia_client *client, struct aki_packet *pack track->client->callback = client->callback; track->client->userdata = client->userdata; track->stream.mode = mode; - if (track->client->init(track->client, client->renderer, &track->stream)) { - client->callback(client->userdata, LIANA_CLIENT_CONFIGURE, track->client->stream, track); + if (!track->client->init(track->client, client->renderer, &track->stream)) { + track->client->free(&track->client); +#if CAMU_HAVE_FFMPEG + if (track->stream.mode == CAMU_FFMPEG_COMPAT) { + avformat_free_context(track->stream.av.format_context); + } +#endif + al_free(track); + continue; } + client->callback(client->userdata, LIANA_CLIENT_CONFIGURE, track->client->stream, track); lia_vcr_add_track(&client->vcr, track); } } @@ -141,6 +150,12 @@ static void connection_closed_callback(void *userdata, struct aki_packet_stream client->callback(client->userdata, LIANA_CLIENT_REMOVE_BUFFERS, NULL, &client->reconnect); if (client->reconnect) { client->reconnect = false; + struct lia_timing time = { + .at = client->at, + .seek_pos = client->pos, + .pause = LIANA_PAUSE_NONE + }; + client->callback(client->userdata, LIANA_CLIENT_RESUME_AT, NULL, &time); aki_packet_stream_reconnect(stream, &client->addr, client->port); } else { client->callback(client->userdata, LIANA_CLIENT_CLOSED, NULL, NULL); @@ -173,10 +188,11 @@ void lia_client_set_renderer(struct lia_client *client, struct camu_renderer *re client->renderer = renderer; } -void lia_client_seek(struct lia_client *client, u64 pos) +void lia_client_seek(struct lia_client *client, u64 pos, u64 at) { client->reconnect = true; client->pos = pos; + client->at = at; aki_packet_stream_disconnect(&client->data); } diff --git a/src/liana/client.h b/src/liana/client.h index 5c16cd8..24526af 100644 --- a/src/liana/client.h +++ b/src/liana/client.h @@ -11,6 +11,7 @@ struct lia_client { u16 id; s32 mask; u64 pos; + u64 at; bool reconnect; str addr; u16 port; @@ -25,7 +26,7 @@ struct lia_client { void lia_client_connect(struct lia_client *client, struct aki_event_loop *loop, u8 type, str *addr, u16 port, u16 id, u64 pos, struct camu_renderer *renderer); -void lia_client_seek(struct lia_client *client, u64 pos); +void lia_client_seek(struct lia_client *client, u64 pos, u64 at); void lia_client_reseek(struct lia_client *client); void lia_client_disconnect(struct lia_client *client); void lia_client_free(struct lia_client *client); diff --git a/src/liana/handler.h b/src/liana/handler.h index 6c23ac5..f994069 100644 --- a/src/liana/handler.h +++ b/src/liana/handler.h @@ -25,11 +25,9 @@ enum { enum { LIANA_CLIENT_CONFIGURE = 0, - LIANA_CLIENT_SET, - LIANA_CLIENT_PAUSE, - LIANA_CLIENT_RESUME, LIANA_CLIENT_DATA, LIANA_CLIENT_REMOVE_BUFFERS, + LIANA_CLIENT_RESUME_AT, LIANA_CLIENT_EOF, LIANA_CLIENT_CLOSED }; diff --git a/src/liana/handlers/cdio_server.c b/src/liana/handlers/cdio_server.c index 1eaf6f3..118f6b5 100644 --- a/src/liana/handlers/cdio_server.c +++ b/src/liana/handlers/cdio_server.c @@ -1,5 +1,4 @@ #include -#include #include "../../cache/entry.h" #include "../../cache/handlers/cdio.h" diff --git a/src/liana/list.c b/src/liana/list.c index 37a144f..18bfd6c 100644 --- a/src/liana/list.c +++ b/src/liana/list.c @@ -59,7 +59,7 @@ void lia_list_add_sink(struct lia_list *list, void (*callback)(void *, u8, struc u64 seek_pos = current->offset; if (current->paused_at == LIANA_TIMESTAMP_INVALID) { now += LIANA_BASE_DELAY; - if (now > current->start) { + if (now > current->start && now - current->start > LIANA_BASE_DELAY) { at = now; seek_pos += now - current->start; } else { @@ -333,7 +333,7 @@ void lia_list_end(struct lia_list *list, s32 sequence) s32 next = sequence + 1; list->previous = sequence; struct lia_list_entry *current = al_array_at(list->entries, list->current); - //current->offset = current->duration; + current->offset = current->duration; if (list->queued >= 0) { list->current = list->queued; list->queued = -1; diff --git a/src/liana/list.h b/src/liana/list.h index 8adea17..eb9a3cb 100644 --- a/src/liana/list.h +++ b/src/liana/list.h @@ -25,25 +25,10 @@ enum { LIANA_META_QUEUED }; -// Pause: -// - Set `paused_at` to now() + PAUSE_DELAY. -// - Increment `offset` by how long the entry will have been -// playing when paused at the requested timestamp (`paused_at` - `start`). -// Resume: -// - Unset `paused_at` -// - Set `start` to now() + PAUSE_DELAY. -// Next/Prev: -// Current Playing, Target Playing: -// - Set `current->held_at` to now() + PAUSE_DELAY. -// - Increment `current->offset` by the same logic as pause. -// - -// Current Playing, Target Paused: -// Current Paused, Target Playing: -// Current Paused, Target Paused: -// Seek: - -// NOTE: keep global per list max time until all sinks _should_ by buffered -// possibly use that instead of LIANA_PAUSE_DELAY. +// NOTE: To handle an entry being queued right before a skip, keep a global +// "max time until all sinks buffered" and used that instead of LIANA_PAUSE_DELAY (if greater). + +// TODO: Factor in LIANA_BASE_PING. enum { LIANA_PAUSE_NONE = 0, diff --git a/src/liana/meson.build b/src/liana/meson.build index 0859e99..da53214 100644 --- a/src/liana/meson.build +++ b/src/liana/meson.build @@ -13,23 +13,12 @@ liana_client_src = [ liana_deps = [codecs] liana_args = [] -libcdio_paranoia = dependency('libcdio_paranoia', required: false, allow_fallback: true) -libcdio_cdda = dependency('libcdio_cdda', required: false, allow_fallback: true) -if libcdio_paranoia.found() and libcdio_cdda.found() +if cache_have_cdio liana_server_src += ['handlers/cdio_server.c'] liana_client_src += ['handlers/cdio_client.c'] - liana_deps += [libcdio_paranoia, libcdio_cdda] liana_args += ['-DLIANA_HAVE_CDIO'] endif -#libdvdcss = dependency('libdvdcss', required: false, allow_fallback: true) -#libdvdread = dependency('libdvdread', required: false, allow_fallback: true) -#libdvdnav = dependency('libdvdnav', required: false, allow_fallback: true) -#if libdvdcss.found() and libdvdread.found() and libdvdnav.found() -# liana_server_src += ['handlers/dvd_server.c'] -# liana_server_deps += [libdvdcss] -#endif - liana_server = declare_dependency(sources: liana_server_src, dependencies: liana_deps, compile_args: [liana_args, '-DLIANA_SERVER']) liana_client = declare_dependency(sources: liana_client_src, dependencies: liana_deps, diff --git a/src/liana/vcr.c b/src/liana/vcr.c index fad8b78..39fe0fe 100644 --- a/src/liana/vcr.c +++ b/src/liana/vcr.c @@ -123,7 +123,11 @@ bool lia_vcr_push_packet(struct lia_vcr *vcr, struct aki_packet *packet) switch (op) { case LIANA_PACKET_DATA: track = get_track_from_index(vcr, aki_packet_read_s32(packet)); - al_assert(track); + if (!track) { + al_log_warn("liana", "Received data from errored or unknown track."); + aki_packet_free(packet); + return false; + } if (!track->running) { aki_thread_create(&track->thread, vcr_track_thread, track); track->running = true; diff --git a/src/libsink/common.h b/src/libsink/common.h index deae228..f8dd9fa 100644 --- a/src/libsink/common.h +++ b/src/libsink/common.h @@ -1,6 +1,6 @@ #pragma once -#define CAMU_SINK_LOCAL 0 +#define CAMU_SINK_LOCAL 1 enum { CAMU_SINK_SET = 0, diff --git a/src/libsink/sink.c b/src/libsink/sink.c index 859b717..990cd69 100644 --- a/src/libsink/sink.c +++ b/src/libsink/sink.c @@ -210,7 +210,7 @@ static void handle_sink_cmd(struct camu_sink *sink, struct camu_sink_cmd *cmd) case SKIP: { if (!sink->conn) return; struct aki_packet *packet = aki_rpc_get_packet(&sink->client, CAMU_SERVER_LIST_ACTION); - aki_packet_write_str(packet, al_str_c("default")); + aki_packet_write_str(packet, &sink->default_list); aki_packet_write_u8(packet, CAMU_LIST_SKIP); //s32 sequence = sink->current ? sink->current->sequence : LIANA_SEQUENCE_ANY; s32 sequence = LIANA_SEQUENCE_ANY; @@ -222,7 +222,7 @@ static void handle_sink_cmd(struct camu_sink *sink, struct camu_sink_cmd *cmd) case SHUFFLE: { if (!sink->conn) return; struct aki_packet *packet = aki_rpc_get_packet(&sink->client, CAMU_SERVER_LIST_ACTION); - aki_packet_write_str(packet, al_str_c("default")); + aki_packet_write_str(packet, &sink->default_list); aki_packet_write_u8(packet, CAMU_LIST_SHUFFLE); aki_rpc_connection_command(sink->conn, packet, NULL, NULL); break; @@ -233,7 +233,7 @@ static void handle_sink_cmd(struct camu_sink *sink, struct camu_sink_cmd *cmd) #else if (!sink->conn) return; struct aki_packet *packet = aki_rpc_get_packet(&sink->client, CAMU_SERVER_LIST_ACTION); - aki_packet_write_str(packet, al_str_c("default")); + aki_packet_write_str(packet, &sink->default_list); aki_packet_write_u8(packet, CAMU_LIST_TOGGLE_PAUSE); s32 sequence = sink->current ? sink->current->sequence : LIANA_SEQUENCE_ANY; aki_packet_write_s32(packet, sequence); @@ -245,7 +245,7 @@ static void handle_sink_cmd(struct camu_sink *sink, struct camu_sink_cmd *cmd) case SEEK: { if (!sink->conn) return; struct aki_packet *packet = aki_rpc_get_packet(&sink->client, CAMU_SERVER_LIST_ACTION); - aki_packet_write_str(packet, al_str_c("default")); + aki_packet_write_str(packet, &sink->default_list); aki_packet_write_u8(packet, CAMU_LIST_SEEK); s32 sequence = sink->current ? sink->current->sequence : LIANA_SEQUENCE_ANY; aki_packet_write_s32(packet, sequence); @@ -256,7 +256,7 @@ static void handle_sink_cmd(struct camu_sink *sink, struct camu_sink_cmd *cmd) case END: { if (!sink->conn) return; struct aki_packet *packet = aki_rpc_get_packet(&sink->client, CAMU_SERVER_LIST_ACTION); - aki_packet_write_str(packet, al_str_c("default")); + aki_packet_write_str(packet, &sink->default_list); aki_packet_write_u8(packet, CAMU_LIST_END); aki_packet_write_s32(packet, cmd->value.i); aki_rpc_connection_command(sink->conn, packet, NULL, NULL); @@ -546,6 +546,12 @@ static void client_callback(void *userdata, u8 op, struct camu_codec_stream *str camu_audio_buffer_reset(&entry->audio.buf); break; } + case LIANA_CLIENT_RESUME_AT: { + struct lia_timing *time = (struct lia_timing *)opaque; + camu_clock_set(&entry->clock, time->seek_pos / 1000000.0); + camu_clock_resume(&entry->clock, time->at); + break; + } case LIANA_CLIENT_EOF: { switch (stream->type) { case CAMU_STREAM_AUDIO: { @@ -917,10 +923,12 @@ static bool seek_command_callback(void *userdata, struct aki_rpc_connection *con struct camu_sink_entry *current = sink->current; aki_mutex_unlock(&sink->mutex); if (current->sequence == sequence) { - // TODO: Thread-safety here. - lia_client_seek(¤t->client, pos); - camu_clock_set(¤t->clock, pos / 1000000.0); - camu_clock_resume(¤t->clock, at); +#if CAMU_SINK_LOCAL + (void)at; + lia_client_seek(¤t->client, pos, 0); +#else + lia_client_seek(¤t->client, pos, at); +#endif } aki_packet_free(packet); diff --git a/src/libsink/sink.h b/src/libsink/sink.h index b9249cd..6d560f6 100644 --- a/src/libsink/sink.h +++ b/src/libsink/sink.h @@ -72,6 +72,7 @@ struct camu_sink { struct aki_signal signal; queue(struct camu_sink_cmd) queue; struct aki_mutex mutex; + str default_list; struct camu_sink_entry *current; struct camu_sink_entry *queued; struct camu_sink_entry *target; diff --git a/src/server/local_compat.c b/src/server/local_compat.c index 9870ce5..39698c5 100644 --- a/src/server/local_compat.c +++ b/src/server/local_compat.c @@ -4,7 +4,9 @@ #include "../cache/handlers/http.h" #endif #include "../cache/handlers/file.h" +#ifdef LIANA_HAVE_CDIO #include "../cache/handlers/cdio.h" +#endif #include "local_compat.h" #include "common.h" @@ -84,14 +86,15 @@ static void worker_signal_callback(void *userdata) static aki_thread_result AKI_THREADCALL queue_thread(void *userdata) { struct camu_local_compat *compat = (struct camu_local_compat *)userdata; + aki_thread_setcanceltype(AKI_THREAD_CANCEL_ASYNCHRONOUS); #ifdef CAMU_HAVE_PORTAL bool have_python = false; #endif u32 count; while (aki_packet_cache_wait(&compat->queue, &count)) { struct aki_packet *packet = aki_packet_cache_pop(&compat->queue); + aki_packet_cache_unlock(&compat->queue); if (!packet) { - aki_packet_cache_unlock(&compat->queue); break; } str local; @@ -99,6 +102,7 @@ static aki_thread_result AKI_THREADCALL queue_thread(void *userdata) struct cch_entry *entry = NULL; struct camu_post *post = NULL; if (al_str_cmp(&local, al_str_c("cdda://"), 0, 7) == 0) { +#ifdef LIANA_HAVE_CDIO entry = cch_handler_cdio_create(); struct cch_chapter *chapter = &al_array_at(entry->chapters, 0); if (local.len > 7) { @@ -109,6 +113,7 @@ static aki_thread_result AKI_THREADCALL queue_thread(void *userdata) } entry->chapter = chapter; entry->handler->maybe_spawn_worker(entry->handler, chapter->start); +#endif } else { #ifdef CAMU_HAVE_PORTAL #ifndef AKIYO_HAS_CURL @@ -141,7 +146,6 @@ static aki_thread_result AKI_THREADCALL queue_thread(void *userdata) #endif #endif } - aki_packet_cache_unlock(&compat->queue); if (entry) { struct camu_server_resource *resource = al_alloc_object(struct camu_server_resource); al_str_clone(&resource->unique_id, &local); @@ -203,7 +207,9 @@ void camu_local_compat_send(struct camu_local_compat *compat, struct aki_packet void camu_local_compat_stop(struct camu_local_compat *compat) { aki_packet_cache_disable(&compat->queue); + aki_thread_cancel(&compat->thread); aki_thread_join(&compat->thread); + aki_signal_stop(&compat->worker_signal); aki_signal_stop(&compat->result_signal); camu_queue_free(compat->results); struct aki_packet *packet; diff --git a/src/sink/desktop.c b/src/sink/desktop.c index 8e628fd..ddde86b 100644 --- a/src/sink/desktop.c +++ b/src/sink/desktop.c @@ -156,6 +156,7 @@ bool camu_desktop_connect(struct camu_desktop *c, u8 type, struct aki_event_loop { c->loop = loop; camu_sink_init(&c->sink, c->loop, &c->mixer, c->renderer); + al_str_from(&c->sink.default_list, "default"); c->sink.callback = sink_callback; c->sink.userdata = c; return camu_sink_connect(&c->sink, type, addr, port, al_str_c("desktop")); -- cgit v1.2.3-101-g0448