/*************************************************************************** * 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 "enginebase.h" #include "bufferconsumer.h" #include #include #include #include #include #include #include #include class QTimer; class QTimerEvent; class GstEnginePipeline; /** * @class GstEngine * @short GStreamer engine plugin * @author Mark Kretschmann */ class GstEngine : public Engine::Base, public BufferConsumer { Q_OBJECT public: GstEngine(); ~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(); } bool CanDecode(const QUrl& url); 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, GstEnginePipeline* pipeline); public slots: void StartPreloading(const QUrl &); bool Load(const QUrl&, Engine::TrackChangeType change, 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); void ReloadSettings(); void AddBufferConsumer(BufferConsumer* consumer); void RemoveBufferConsumer(BufferConsumer* consumer); protected: void SetVolumeSW(uint percent); void timerEvent(QTimerEvent*); private slots: void EndOfStreamReached(bool has_next_track); void HandlePipelineError(const QString& message); void NewMetaData(const Engine::SimpleMetaBundle& bundle); void ClearScopeBuffers(); void AddBufferToScope(GstBuffer* buf, GstEnginePipeline* pipeline); void FadeoutFinished(); void SeekNow(); void BackgroundStreamFinished(); void BackgroundStreamPlayDone(); void PlayDone(); private: // Callbacks static void CanDecodeNewPadCallback(GstElement*, GstPad*, gboolean, gpointer); static void CanDecodeLastCallback(GstElement*, gpointer); static GstBusSyncReply CanDecodeBusCallbackSync(GstBus*, GstMessage*, gpointer); static gboolean CanDecodeBusCallback(GstBus*, GstMessage*, gpointer); static void PrintGstError(GstMessage* msg); static void SetEnv(const char* key, const QString& value); PluginDetailsList GetPluginList(const QString& classname) const; void InitialiseGstreamer(); void StartFadeout(); void StartTimers(); void StopTimers(); boost::shared_ptr CreatePipeline(); boost::shared_ptr CreatePipeline(const QUrl& url); void UpdateScope(); qint64 PruneScope(); int AddBackgroundStream(boost::shared_ptr pipeline); static QUrl FixupUrl(const QUrl& url); private: static const int kTimerIntervalNanosec = 1000 * 1e6; // 1s static const int kPreloadGapNanosec = 1000 * 1e6; // 1s static const int kSeekDelayNanosec = 100 * 1e6; // 100msec static const char* kHypnotoadPipeline; QFuture initialising_; QString sink_; QString device_; boost::shared_ptr current_pipeline_; boost::shared_ptr fadeout_pipeline_; boost::shared_ptr preload_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_; bool rg_enabled_; int rg_mode_; float rg_preamp_; bool rg_compression_; qint64 buffer_duration_nanosec_; 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_; }; #endif /*AMAROK_GSTENGINE_H*/