/*************************************************************************** * Copyright (C) 2003-2005 by Mark Kretschmann * * Copyright (C) 2005 by Jakub Stachowski * * Portions Copyright (C) 2006 Paul Cifarelli * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Steet, Fifth Floor, Boston, MA 02111-1307, USA. * ***************************************************************************/ #ifndef AMAROK_GSTENGINE_H #define AMAROK_GSTENGINE_H #include "bufferconsumer.h" #include "enginebase.h" #include "core/boundfuturewatcher.h" #include "core/timeconstants.h" #include #include #include #include #include #include #include #include class QTimer; class QTimerEvent; class GstEnginePipeline; class TaskManager; /** * @class GstEngine * @short GStreamer engine plugin * @author Mark Kretschmann */ class GstEngine : public Engine::Base, public BufferConsumer { Q_OBJECT public: GstEngine(TaskManager* task_manager); ~GstEngine(); struct PluginDetails { QString name; QString long_name; QString author; QString description; }; typedef QList PluginDetailsList; static const char* kSettingsGroup; static const char* kAutoSink; bool Init(); void EnsureInitialised() { initialising_.waitForFinished(); } static void InitialiseGstreamer(); int AddBackgroundStream(const QUrl& url); void StopBackgroundStream(int id); void SetBackgroundStreamVolume(int id, int volume); qint64 position_nanosec() const; qint64 length_nanosec() const; Engine::State state() const; const Engine::Scope& scope(); PluginDetailsList GetOutputsList() const { return GetPluginList( "Sink/Audio" ); } static bool DoesThisSinkSupportChangingTheOutputDeviceToAUserEditableString(const QString& name); GstElement* CreateElement(const QString& factoryName, GstElement* bin = 0); // BufferConsumer void ConsumeBuffer(GstBuffer *buffer, int pipeline_id); public slots: void StartPreloading(const QUrl& url, bool force_stop_at_end, qint64 beginning_nanosec, qint64 end_nanosec); bool Load(const QUrl&, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec); bool Play(quint64 offset_nanosec); void Stop(); void Pause(); void Unpause(); void Seek(quint64 offset_nanosec); /** Set whether equalizer is enabled */ void SetEqualizerEnabled(bool); /** Set equalizer preamp and gains, range -100..100. Gains are 10 values. */ void SetEqualizerParameters(int preamp, const QList& bandGains); /** Set Stereo balance, range -1.0f..1.0f */ void SetStereoBalance(float value); void ReloadSettings(); void AddBufferConsumer(BufferConsumer* consumer); void RemoveBufferConsumer(BufferConsumer* consumer); protected: void SetVolumeSW(uint percent); void timerEvent(QTimerEvent*); private slots: void EndOfStreamReached(int pipeline_id, bool has_next_track); void HandlePipelineError(int pipeline_id, const QString& message, int domain, int error_code); void NewMetaData(int pipeline_id, const Engine::SimpleMetaBundle& bundle); void ClearScopeBuffers(); void AddBufferToScope(GstBuffer* buf, int pipeline_id); void FadeoutFinished(); void FadeoutPauseFinished(); void SeekNow(); void BackgroundStreamFinished(); void BackgroundStreamPlayDone(); void PlayDone(); void BufferingStarted(); void BufferingProgress(int percent); void BufferingFinished(); private: typedef QPair PlayFutureWatcherArg; typedef BoundFutureWatcher PlayFutureWatcher; static void SetEnv(const char* key, const QString& value); PluginDetailsList GetPluginList(const QString& classname) const; void StartFadeout(); void StartFadeoutPause(); void StartTimers(); void StopTimers(); boost::shared_ptr CreatePipeline(); boost::shared_ptr CreatePipeline(const QUrl& url, qint64 end_nanosec); void UpdateScope(); qint64 PruneScope(); int AddBackgroundStream(boost::shared_ptr pipeline); static QUrl FixupUrl(const QUrl& url); private: static const int kTimerIntervalNanosec = 1000 * kNsecPerMsec; // 1s static const int kPreloadGapNanosec = 1000 * kNsecPerMsec; // 1s static const int kSeekDelayNanosec = 100 * kNsecPerMsec; // 100msec static const char* kHypnotoadPipeline; static const char* kEnterprisePipeline; TaskManager* task_manager_; int buffering_task_id_; QFuture initialising_; QString sink_; QString device_; boost::shared_ptr current_pipeline_; boost::shared_ptr fadeout_pipeline_; boost::shared_ptr fadeout_pause_pipeline_; QUrl preloaded_url_; QList buffer_consumers_; GQueue* delayq_; float current_scope_[kScopeSize]; int current_sample_; bool equalizer_enabled_; int equalizer_preamp_; QList equalizer_gains_; float stereo_balance_; bool rg_enabled_; int rg_mode_; float rg_preamp_; bool rg_compression_; qint64 buffer_duration_nanosec_; bool mono_playback_; mutable bool can_decode_success_; mutable bool can_decode_last_; // Hack to stop seeks happening too often QTimer* seek_timer_; bool waiting_to_seek_; quint64 seek_pos_; int timer_id_; int next_element_id_; QHash > background_streams_; bool is_fading_out_to_pause_; bool has_faded_out_; }; #endif /*AMAROK_GSTENGINE_H*/