#pragma once #include "media/types.hpp" #include "media/plugin_manager.hpp" #include #include #include #include #include #include namespace media { /** * Radio Engine Configuration */ struct RadioEngineConfig { // General int max_channels = 10; // Default audio settings int default_bitrate_kbps = 128; int default_sample_rate = 44100; int default_channels = 2; std::string default_codec = "mp3"; // Crossfade bool crossfade_enabled = true; int crossfade_duration_ms = 3000; // Normalization bool normalization_enabled = true; double target_lufs = -14.0; // Output std::string hls_output_dir = "/data/hls/radio"; int hls_segment_duration = 6; // Notification callback NotificationCallback notification_callback; }; /** * Internal Radio Channel State */ struct RadioChannelState { RadioChannelConfig config; RadioChannelStatus status; // Playlist std::vector playlist; size_t current_index = 0; // Streaming state std::atomic is_running{false}; std::thread stream_thread; std::condition_variable cv; std::mutex mutex; // FFmpeg process handle (or similar) void* process_handle = nullptr; // Statistics std::chrono::system_clock::time_point started_at; std::atomic listener_count{0}; }; /** * Radio Engine * * Manages radio channel streaming with playlist scheduling, * crossfading, audio normalization, and multiple output formats. */ class RadioEngine { public: RadioEngine(); ~RadioEngine(); // Disable copying RadioEngine(const RadioEngine&) = delete; RadioEngine& operator=(const RadioEngine&) = delete; // ======================================================================== // Initialization // ======================================================================== /** * Initialize the radio engine * @param config Engine configuration * @param plugin_manager Plugin manager for audio processing * @return Result indicating success or failure */ Result initialize( const RadioEngineConfig& config, PluginManager* plugin_manager ); /** * Shutdown all channels and cleanup */ void shutdown(); // ======================================================================== // Channel Management // ======================================================================== /** * Create a new radio channel * @param config Channel configuration * @return Result with channel ID or error */ Result create_channel(const RadioChannelConfig& config); /** * Delete a radio channel * @param channel_id Channel ID * @return Result indicating success or failure */ Result delete_channel(const std::string& channel_id); /** * Update channel configuration * @param channel_id Channel ID * @param config New configuration * @return Result indicating success or failure */ Result update_channel( const std::string& channel_id, const RadioChannelConfig& config ); /** * Get channel status * @param channel_id Channel ID * @return Result with channel status or error */ Result get_channel_status( const std::string& channel_id ) const; /** * List all channels * @param tenant_id Filter by tenant (empty for all) * @return Vector of channel statuses */ std::vector list_channels( const std::string& tenant_id = "" ) const; // ======================================================================== // Streaming Control // ======================================================================== /** * Start streaming a channel * @param channel_id Channel ID * @return Result with stream URL or error */ Result start_channel(const std::string& channel_id); /** * Stop streaming a channel * @param channel_id Channel ID * @return Result indicating success or failure */ Result stop_channel(const std::string& channel_id); // ======================================================================== // Playlist Management // ======================================================================== /** * Set channel playlist * @param channel_id Channel ID * @param tracks List of tracks * @return Result indicating success or failure */ Result set_playlist( const std::string& channel_id, const std::vector& tracks ); /** * Add track to playlist * @param channel_id Channel ID * @param track Track to add * @param position Position in playlist (-1 for end) * @return Result indicating success or failure */ Result add_track( const std::string& channel_id, const RadioTrack& track, int position = -1 ); /** * Remove track from playlist * @param channel_id Channel ID * @param track_id Track ID to remove * @return Result indicating success or failure */ Result remove_track( const std::string& channel_id, const std::string& track_id ); /** * Skip to next track * @param channel_id Channel ID * @return Result indicating success or failure */ Result skip_track(const std::string& channel_id); /** * Get current playlist * @param channel_id Channel ID * @return Result with playlist or error */ Result> get_playlist( const std::string& channel_id ) const; /** * Get now playing info * @param channel_id Channel ID * @return Result with current track or error */ Result get_now_playing( const std::string& channel_id ) const; // ======================================================================== // Auto-DJ // ======================================================================== /** * Enable/disable auto-DJ for a channel * @param channel_id Channel ID * @param enabled Enable auto-DJ * @param folders Folders to scan for music * @param shuffle Shuffle tracks * @return Result indicating success or failure */ Result set_auto_dj( const std::string& channel_id, bool enabled, const std::vector& folders = {}, bool shuffle = true ); // ======================================================================== // Statistics // ======================================================================== /** * Update listener count (called by stream server) * @param channel_id Channel ID * @param delta Change in listener count */ void update_listener_count(const std::string& channel_id, int delta); /** * Get total listener count across all channels */ int get_total_listeners() const; private: /** * Stream thread function */ void stream_thread(const std::string& channel_id); /** * Load next track with crossfade */ void load_next_track(RadioChannelState& state); /** * Apply audio processing (normalization, effects) */ void process_audio(RadioChannelState& state, void* buffer, size_t size); /** * Generate HLS segments */ void generate_hls_segment( const std::string& channel_id, const void* audio_data, size_t size ); /** * Scan folder for audio files */ std::vector scan_folder(const std::string& folder); /** * Get audio metadata from file */ RadioTrack get_track_metadata(const std::string& path); // Configuration RadioEngineConfig config_; PluginManager* plugin_manager_ = nullptr; // State std::atomic initialized_{false}; // Channels mutable std::mutex channels_mutex_; std::map> channels_; }; } // namespace media