mirror of
https://github.com/toyota-connected/ivi-homescreen-plugins.git
synced 2026-06-21 07:19:32 -07:00
Audit pass against the plugin turned up three latent lifetime/ownership bugs and a handful of data races. Rewriting AudioPlayer to hold shared state by shared_ptr fixes them. Lifetime / ownership -------------------- Previously, SendEvent and OnError queued g_idle_add_full callbacks that captured `this` by pointer. StartDurationDiscovery spawned a detached thread writing to `&discovered_duration_ms_`. All three would dereference freed memory if the AudioPlayer was destroyed before the callback/thread fired. Fix: introduce a SharedState struct (event sink + mutex + cancelled flag + channel name + discovered_duration_ms atomic) owned by a shared_ptr on the AudioPlayer. Idle callbacks and the discovery thread capture the shared_ptr by value, extending the state's lifetime past AudioPlayer destruction. The destructor sets cancelled=true and clears the sink under the mutex; late-firing callbacks observe cancelled and become no-ops. Also introduces a small PostToMainLoop helper that wraps g_idle_add_full over a heap-allocated std::function, removing the ad-hoc new-Ctx / delete-Ctx pattern in three places. Data races ---------- isPlaying_, isInitialized_, isLooping_, isSeekCompleted_ were plain bools accessed from the Flutter platform thread, the GStreamer bus thread, and the streaming thread (AboutToFinish). Now std::atomic<bool> with relaxed ordering (no synchronization semantics needed — they only guard branches on other code paths that already have their own synchronization). The isSeekCompleted→true transition in OnBusMessage uses compare_exchange_strong so the OnSeekCompleted callback fires at most once. url_ (std::string) was written by SetSourceUrl on the platform thread and read by AboutToFinish on the streaming thread. Now guarded by url_mu_; AboutToFinish snapshots under the lock before setting playbin's uri property. Dead code --------- Removed: - GMainContext* context_ (captured in ctor, never read) - GstElement* source_ and its Dispose-time unref (only ever assigned by a signal handler that has been empty since the Phase-2 SSL fix, so source_ was always null) - g_signal_connect for "source-setup" and the empty SourceSetup callback itself - #include <fstream> Tooling ------- - clang-tidy is clean (was: modernize-pass-by-value on the ctor, readability-use-anyofallof on the scheme whitelist loop — both fixed) - clang-format applied across all plugin files No functional change intended beyond the lifetime/race fixes. Runtime-tested against the upstream Bluefire example: replay, gapless loop, VBR MP3 duration, invalid-source error, multi-source swap all still work. Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
audioplayers_linux
This plugin is used with the pub.dev package audioplayers
https://pub.dev/packages/audioplayers
Functional Test Case
https://github.com/bluefireteam/audioplayers/tree/main/packages/audioplayers/example