#pragma once #include <functional> #include <memory> #include <mutex> #include <atomic> #include <BellUtils.h> #include <WrappedSemaphore.h> #include "CDNTrackStream.h" #include "CSpotContext.h" #include "TrackProvider.h" #include "TrackReference.h" #ifdef BELL_VORBIS_FLOAT #include "vorbis/vorbisfile.h" #else #include "ivorbisfile.h" #endif namespace cspot { class TrackPlayer : bell::Task { public: typedef std::function<void()> TrackLoadedCallback; typedef std::function<size_t(uint8_t*, size_t, std::string_view, size_t)> DataCallback; typedef std::function<void()> EOFCallback; typedef std::function<bool()> isAiringCallback; TrackPlayer(std::shared_ptr<cspot::Context> ctx, isAiringCallback, EOFCallback, TrackLoadedCallback); ~TrackPlayer(); void loadTrackFromRef(TrackReference& ref, size_t playbackMs, bool startAutomatically); void setDataCallback(DataCallback callback); CDNTrackStream::TrackInfo getCurrentTrackInfo(); void seekMs(size_t ms); void stopTrack(); // Vorbis codec callbacks size_t _vorbisRead(void* ptr, size_t size, size_t nmemb); size_t _vorbisClose(); int _vorbisSeek(int64_t offset, int whence); long _vorbisTell(); void destroy(); private: std::shared_ptr<cspot::Context> ctx; std::shared_ptr<cspot::TrackProvider> trackProvider; std::shared_ptr<cspot::CDNTrackStream> currentTrackStream; size_t sequence = std::time(nullptr); std::unique_ptr<bell::WrappedSemaphore> playbackSemaphore; TrackLoadedCallback trackLoaded; DataCallback dataCallback = nullptr; EOFCallback eofCallback; isAiringCallback isAiring; // Playback control std::atomic<bool> currentSongPlaying; std::mutex playbackMutex; std::mutex seekMutex; // Vorbis related OggVorbis_File vorbisFile; ov_callbacks vorbisCallbacks; int currentSection; std::vector<uint8_t> pcmBuffer = std::vector<uint8_t>(1024); size_t playbackPosition = 0; bool autoStart = false; std::atomic<bool> isRunning = true; std::mutex runningMutex; void runTask() override; }; } // namespace cspot