Skip to content

Commit 44c76a5

Browse files
committed
[CHORE:DOCS] add mpris docs + refactor code
the bullshit class name of song tree has been changed to `SongLibrarySnapshot` (will remove the core namespace from it in future commits.)
1 parent 37618f1 commit 44c76a5

14 files changed

Lines changed: 191 additions & 60 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ include(${CMAKE_SOURCE_DIR}/cmake/Version.cmake)
202202
# Backend Shared Library
203203
# -----------------------------------------------------------
204204
set(INLIMBO_CORE_SOURCES
205-
src/core/SongTree.cc
205+
src/core/SongLibrarySnapshot.cc
206206
src/audio/backend/alsa/Impl.cc
207207
src/audio/backend/Interface.cc
208208
src/audio/Registry.cc

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,15 @@ More *could* be added if that is required but these are the most used fields.
214214

215215
Now each field has certain criteria upon which the map is reordered.
216216

217-
1. Artist: `Lexicographically Ascending/Descending (ASCII only)`, `Albums Count Ascending/Descending`, `Track Count Ascending/Descending`
218-
2. Album: `Lexicographically Ascending/Descending (ASCII only)`, `Track Count Ascending/Descending`
219-
3. Track: `Track Number Ascending/Descending`
217+
1. Artist:
218+
- `Lexicographically Ascending/Descending (ASCII only)`
219+
- `Albums Count Ascending/Descending`
220+
- `Track Count Ascending/Descending`
221+
2. Album:
222+
- `Lexicographically Ascending/Descending (ASCII only)`
223+
- `Track Count Ascending/Descending`
224+
3. Track:
225+
- `Track Number Ascending/Descending`
220226

221227
These are self-explanatory and easy to understand what each sort does. You can check out [example config.toml](https://github.com/nots1dd/inLimbo/blob/main/examples/config/config.toml) for how to customize each sort.
222228

include/inlimbo/audio/backend/Interface.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class IAudioBackend
6161

6262
[[nodiscard]] virtual auto getBackendInfo() const -> backend::BackendInfo = 0;
6363

64-
/* ---------------- Visualization support ---------------- */
64+
/* ---------------- Audio buffer read ---------------- */
6565

6666
[[nodiscard]] virtual auto copySequence() const noexcept -> ui64 = 0;
6767
[[nodiscard]] virtual auto copyBufferSize() const noexcept -> size_t = 0;

include/inlimbo/core/SongTree.hpp renamed to include/inlimbo/core/SongLibrarySnapshot.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ namespace core
1818
{
1919

2020
// ============================================================
21-
// SongTree Declaration (NOT THREAD SAFE)
21+
// SongLibrarySnapshot Declaration (NOT THREAD SAFE)
2222
// ============================================================
2323
//
2424
// Note that this structure is used ONLY for serialization and deserialization.
2525
// The in-memory representation used during runtime is a threads::SafeMap<SongMap>.
2626
//
2727

28-
class SongTree
28+
class SongLibrarySnapshot
2929
{
3030
private:
3131
SongMap m_songMap;
@@ -36,30 +36,30 @@ class SongTree
3636
void addSong(const Song& song);
3737
void setMusicPath(const Path& path) { m_musicPath = path; }
3838

39-
~SongTree() { clear(); }
39+
~SongLibrarySnapshot() { clear(); }
4040

4141
void clear()
4242
{
43-
RECORD_FUNC_TO_BACKTRACE("SongTree::clear");
43+
RECORD_FUNC_TO_BACKTRACE("SongLibrarySnapshot::clear");
4444
m_songMap.clear();
4545
m_musicPath.clear();
4646
}
4747

4848
// Query methods
4949
[[nodiscard]] auto returnSongMap() const -> const SongMap&
5050
{
51-
RECORD_FUNC_TO_BACKTRACE("SongTree::returnSongMap");
51+
RECORD_FUNC_TO_BACKTRACE("SongLibrarySnapshot::returnSongMap");
5252
return m_songMap;
5353
}
5454
[[nodiscard]] auto moveSongMap() noexcept -> SongMap
5555
{
56-
RECORD_FUNC_TO_BACKTRACE("SongTree::moveSongMap");
56+
RECORD_FUNC_TO_BACKTRACE("SongLibrarySnapshot::moveSongMap");
5757
return std::move(m_songMap);
5858
}
5959
// note that this replaces the entire song map and newMap is no longer valid after this call
6060
void newSongMap(const SongMap& newMap)
6161
{
62-
RECORD_FUNC_TO_BACKTRACE("SongTree::replaceSongMap");
62+
RECORD_FUNC_TO_BACKTRACE("SongLibrarySnapshot::replaceSongMap");
6363
m_songMap = std::move(newMap);
6464
}
6565
[[nodiscard]] auto returnMusicPath() const -> const Path { return m_musicPath; }
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#pragma once
22

33
#include "InLimbo-Types.hpp"
4-
#include "core/SongTree.hpp"
4+
#include "core/SongLibrarySnapshot.hpp"
55
#include "taglib/Parser.hpp"
66

77
namespace helpers::fs
88
{
99

10-
void dirWalkProcessAll(const Directory& directory, taglib::Parser& parser,
11-
core::SongTree& songTree);
10+
void dirWalkProcessAll(const Directory& directory, taglib::Parser& tagParser,
11+
core::SongLibrarySnapshot& songLibrarySnapshot);
1212

1313
} // namespace helpers::fs

include/inlimbo/mpris/Interface.hpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#pragma once
22

33
#include "InLimbo-Types.hpp"
4-
#include <string>
54

65
namespace mpris
76
{
@@ -28,10 +27,10 @@ class IMprisBackend
2827
[[nodiscard]] virtual auto durationSeconds() const -> double = 0;
2928

3029
/* Metadata */
31-
[[nodiscard]] virtual auto title() const -> Title = 0;
32-
[[nodiscard]] virtual auto artist() const -> Artist = 0;
33-
[[nodiscard]] virtual auto album() const -> Album = 0;
34-
[[nodiscard]] virtual auto artUrl() const -> std::string = 0;
30+
[[nodiscard]] virtual auto title() const -> Title = 0;
31+
[[nodiscard]] virtual auto artist() const -> Artist = 0;
32+
[[nodiscard]] virtual auto album() const -> Album = 0;
33+
[[nodiscard]] virtual auto artUrl() const -> PathStr = 0;
3534

3635
/* Volume */
3736
[[nodiscard]] virtual auto volume() const -> double = 0; // 0.0 → 1.0

include/inlimbo/mpris/Service.hpp

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,123 @@
33
#include "Interface.hpp"
44
#include "c/mpris.h"
55

6+
// MPRIS Service
7+
//
8+
// The structure of how we get to this service is:
9+
//
10+
// ┌──────────────────────────────┐
11+
// │ DBus / MPRIS │
12+
// │ (org.mpris.MediaPlayer2) │
13+
// └──────────────▲───────────────┘
14+
//
15+
// │ calls / signals
16+
//
17+
// ┌──────────────┴───────────────┐
18+
// │ mpris_service (C) │ ← opaque handle
19+
// │ - DBus glue │
20+
// │ - State cache │
21+
// └──────────────▲───────────────┘
22+
//
23+
// │ function pointers
24+
//
25+
// ┌──────────────┴───────────────┐
26+
// │ mpris_backend (C) │ ← C ABI boundary
27+
// │ - userdata (IMprisBackend*) │
28+
// │ - play(), pause(), title() │
29+
// └──────────────▲───────────────┘
30+
//
31+
// │ dispatch
32+
//
33+
// ┌──────────────┴───────────────┐
34+
// │ mpris::Service (C++) │ ← CPP boundary
35+
// │ - owns mpris_service* │
36+
// │ - owns backend reference │
37+
// └──────────────▲───────────────┘
38+
//
39+
// │ virtual calls
40+
//
41+
// ┌──────────────┴───────────────┐
42+
// │ IMprisBackend (C++) │ ← Strategy interface
43+
// │ - play(), seek(), metadata │
44+
// └──────────────▲───────────────┘
45+
//
46+
// │ concrete impl
47+
//
48+
// ┌──────────────┴───────────────┐
49+
// │ audio::Service calls │
50+
// └──────────────────────────────┘
51+
//
52+
// Why was the C ABI made?
53+
//
54+
// Initially, the choice was made due to a simple reason.
55+
// I did not want to use gio or glib for this, it was too
56+
// tacky and felt too much for a simple DBus connection
57+
// and event poller/notifier.
58+
//
59+
// So i just wanted to write it in pure c using libdbus
60+
// API directly instead and statically compile it as a
61+
// separate library.
62+
//
63+
// An added benefit was that I can change the logic however
64+
// I want when these events are handled in cpp boundary,
65+
// without worrying about messing up the DBus core logic.
66+
//
67+
// But quite honestly, this isnt required still and I could
68+
// have just written externed C code over to cpp itself,
69+
// and had one core backend implementation (backend::Common)
70+
//
71+
// It currently is very stable and works pretty well, so
72+
// I do not have any intention of changing this however.
73+
// (unless some good points are made on why this is shitty)
74+
//
75+
// Also the frontend does not have to worry about all this,
76+
// which is another added benefit of just abstracting it all
77+
// behind an interface and language boundary.
78+
//
79+
// 1. How to create a MPRIS service?
80+
//
81+
// -> Create the backend implementation first
82+
// (or just use mpris::backend::Common)
83+
//
84+
// Note that the backend must inherit `IMprisBackend`
85+
// and ofc override all methods.
86+
//
87+
// -> Have an App name ready.
88+
//
89+
// Then simply invoke like so:
90+
//
91+
// ```cpp
92+
// mpris::backend::Common mprisBackend(audioService);
93+
// mpris::Service mprisService(mprisBackend, "test");
94+
// ```
95+
//
96+
// FAQ:
97+
//
98+
// - Will I need to create new mpris service objs in
99+
// the frontend?
100+
//
101+
// NO. The inLimbo main context will handle it at compile
102+
// time. Frontend will ONLY receive that mpris service
103+
// as a pointer over the frontend C ABI.
104+
//
105+
// In short, you do not need to worry about creation
106+
// or deletion of this object. The lifetime is strictly
107+
// handled by the main context at all times.
108+
//
109+
// - Why would I ever need to create a custom MPRIS
110+
// backend?
111+
//
112+
// Maybe to add some logging, connect to lastfm API,
113+
// idk. Possibilities with such a model is ofc quite
114+
// extensive and I will leave it upto you to decide.
115+
6116
namespace mpris
7117
{
8118

9119
class Service
10120
{
11121
public:
12-
Service(IMprisBackend& backend, const std::string& name);
122+
Service(IMprisBackend& backend, const std::string& appName);
13123
~Service();
14124

15125
void poll();

include/inlimbo/mpris/backends/Common.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class Common final : public mpris::IMprisBackend
6969
return m ? m->album : "";
7070
}
7171

72-
[[nodiscard]] auto artUrl() const -> std::string override
72+
[[nodiscard]] auto artUrl() const -> PathStr override
7373
{
7474
auto m = m_audioService.getCurrentMetadata();
7575
return m ? m->artUrl : "";

src/Context.cc

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,10 @@ auto maybeHandleEditActions(AppContext& ctx) -> bool
462462
}
463463

464464
// Persist updated SongMap to disk
465-
SongTree tempSongTree;
466-
tempSongTree.clear();
467-
tempSongTree.newSongMap(g_songMap.snapshot());
468-
tempSongTree.saveToFile(ctx.m_binPath);
465+
SongLibrarySnapshot tempSongLib;
466+
tempSongLib.clear();
467+
tempSongLib.newSongMap(g_songMap.snapshot());
468+
tempSongLib.saveToFile(ctx.m_binPath);
469469

470470
LOG_DEBUG("Song object metadata updated successfully. Exiting app...");
471471
return true;
@@ -545,13 +545,13 @@ auto initializeContext(int argc, char** argv) -> AppContext
545545

546546
void buildOrLoadLibrary(AppContext& ctx)
547547
{
548-
SongTree tempSongTree;
549-
bool rebuild = ctx.args.rebuildLibrary;
548+
SongLibrarySnapshot tempSongLib;
549+
bool rebuild = ctx.args.rebuildLibrary;
550550

551551
try
552552
{
553-
tempSongTree.loadFromFile(ctx.m_binPath);
554-
if (tempSongTree.returnMusicPath() != ctx.m_musicDir)
553+
tempSongLib.loadFromFile(ctx.m_binPath);
554+
if (tempSongLib.returnMusicPath() != ctx.m_musicDir)
555555
rebuild = true;
556556
}
557557
catch (...)
@@ -562,26 +562,28 @@ void buildOrLoadLibrary(AppContext& ctx)
562562
if (!rebuild)
563563
{
564564
LOG_INFO("No song map rebuild. Loading song map and sorting...");
565-
g_songMap.replace(tempSongTree.moveSongMap());
565+
g_songMap.replace(tempSongLib.moveSongMap());
566+
// loads any changes in sorting plan from config
566567
const auto plan = config::sort::loadRuntimeSortPlan();
567568
query::songmap::mut::sortSongMap(g_songMap, plan);
568569
return;
569570
}
570571

571572
utils::Timer<> timer;
572573
timer.start();
573-
tempSongTree.clear();
574+
tempSongLib.clear();
574575

575-
helpers::fs::dirWalkProcessAll(ctx.m_musicDir, ctx.m_tagLibParser, tempSongTree);
576+
helpers::fs::dirWalkProcessAll(ctx.m_musicDir, ctx.m_tagLibParser, tempSongLib);
576577

577-
tempSongTree.setMusicPath(ctx.m_musicDir);
578-
g_songMap.replace(tempSongTree.moveSongMap());
579-
// the song map is unordered so lets sort it
578+
tempSongLib.setMusicPath(ctx.m_musicDir);
579+
g_songMap.replace(tempSongLib.moveSongMap());
580+
// the fresh song map is unordered so lets sort it
580581
//
581582
// note that by default, we are only sorting this following:
582583
//
583584
// -> artists in ascending order (lexicographically),
584585
// -> albums in ascending order (lexicographically),
586+
// -> discs in ascending order (numerically),
585587
// -> tracks in ascending order (numerically)
586588
//
587589
// as that is most logical.
@@ -592,10 +594,10 @@ void buildOrLoadLibrary(AppContext& ctx)
592594
query::songmap::mut::sortSongMap(g_songMap, plan);
593595

594596
// now let us save the newly sorted song map to disk
595-
tempSongTree.newSongMap(g_songMap.snapshot());
596-
tempSongTree.saveToFile(ctx.m_binPath);
597+
tempSongLib.newSongMap(g_songMap.snapshot());
598+
tempSongLib.saveToFile(ctx.m_binPath);
597599

598-
// SongTree has destructor so mem shud clear here
600+
// SongLibrarySnapshot has destructor so mem shud clear here
599601
LOG_INFO("Library rebuilt in {:.3f} ms", timer.elapsed_ms());
600602
}
601603

@@ -637,10 +639,13 @@ void runFrontend(AppContext& ctx)
637639
LOG_INFO("Fuzzy search song title query returned: '{}'", song->metadata.title);
638640

639641
// ---------------------------------------------------------
640-
// Create AudioService (owns AudioEngine)
642+
// Create audio::Service
641643
// ---------------------------------------------------------
642644
audio::Service audio(g_songMap, ctx.m_audioBackendName);
643645

646+
// ---------------------------------------------------------
647+
// Create mpris::Service (common backend logic)
648+
// ---------------------------------------------------------
644649
mpris::backend::Common mprisBackend(audio);
645650
mpris::Service mprisService(mprisBackend, APP_NAME);
646651

@@ -707,15 +712,15 @@ void runFrontend(AppContext& ctx)
707712
}
708713
catch (const utils::unix::LockFileError& e)
709714
{
710-
LOG_ERROR("Context threw LockFileError: {}", e.what());
715+
LOG_ERROR("unix::LockFileError: {}", e.what());
711716
}
712717
catch (const frontend::PluginError& e)
713718
{
714719
LOG_ERROR("frontend::PluginError: Context threw Frontend error: {}", e.what());
715720
}
716721
catch (std::exception& e)
717722
{
718-
LOG_ERROR("Context threw generic std::exception: '{}'", e.what());
723+
LOG_ERROR("inlimbp::runFrontend threw std::exception: '{}'", e.what());
719724
}
720725
}
721726

src/audio/Service.cc

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,17 @@ Service::Service(threads::SafeMap<SongMap>& songMapTS, const std::string& backen
1616
{
1717
LOG_DEBUG("Found ALSA backend. Creating audio service...");
1818
m_backend = std::make_shared<backend::AlsaBackend>();
19-
LOG_INFO("Audio Backend '{}' (ID: {}) created.", m_backend->backendString(),
20-
(int)m_backend->backendID());
2119
}
20+
else
21+
{
22+
// always default to ALSA for now
23+
// (we will assume that inLimbo builds for ALSA at the bare minimum.)
24+
LOG_WARN("audio::Service: Invalid audio backend name found, defaulting to ALSA...");
25+
m_backend = std::make_shared<backend::AlsaBackend>();
26+
}
27+
28+
LOG_INFO("Audio Backend '{}' (ID: {}) created.", m_backend->backendString(),
29+
(int)m_backend->backendID());
2230
}
2331

2432
Service::~Service() { shutdown(); }

0 commit comments

Comments
 (0)