[banshee] gst#: Add initial cdda support



commit 1ab1670cafaf16482c689f2b2c35c61332b970a0
Author: Olivier Dufour <olivier duff gmail com>
Date:   Fri May 20 19:52:12 2011 +0200

    gst#: Add initial cdda support
    
    Signed-off-by: Bertrand Lorentz <bertrand lorentz gmail com>

 .../Banshee.GStreamerSharp.csproj                  |    1 +
 .../Banshee.GStreamerSharp/CddaManager.cs          |  178 ++++++++++++++++++++
 .../Banshee.GStreamerSharp/PlayerEngine.cs         |    8 +
 src/Backends/Banshee.GStreamerSharp/Makefile.am    |    1 +
 4 files changed, 188 insertions(+), 0 deletions(-)
---
diff --git a/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp.csproj b/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp.csproj
index d59e593..b87d04e 100644
--- a/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp.csproj
+++ b/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp.csproj
@@ -72,6 +72,7 @@
   <ItemGroup>
     <Compile Include="Banshee.GStreamerSharp\PlayerEngine.cs" />
     <Compile Include="Banshee.GStreamerSharp\BpmDetector.cs" />
+    <Compile Include="Banshee.GStreamerSharp\CddaManager.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
 </Project>
diff --git a/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp/CddaManager.cs b/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp/CddaManager.cs
new file mode 100644
index 0000000..2a7ae4b
--- /dev/null
+++ b/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp/CddaManager.cs
@@ -0,0 +1,178 @@
+//
+// CddaManager.cs
+//
+// Author:
+//   Olivier Dufour <olivier duff gmail com>
+//
+// Copyright 2011
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+
+using Gst;
+using Gst.Cdda;
+using Gst.BasePlugins;
+
+using Hyena;
+
+namespace Banshee.GStreamerSharp
+{
+    public class CddaManager
+    {
+        public CddaManager (PlayBin2 playbin)
+        {
+            if (playbin != null) {
+                playbin.AddNotification ("source", OnSourceChanged);
+            }
+        }
+
+        public string Device {
+            get; set;
+        }
+
+        private CddaBaseSrc GetCddaSource (Element playbin)
+        {
+            CddaBaseSrc source = null;
+
+            if (playbin == null) {
+                return null;
+            }
+
+            source = playbin ["source"] as CddaBaseSrc;
+
+            return source;
+        }
+
+        private void OnSourceChanged (object o, Gst.GLib.NotifyArgs args)
+        {
+            if (Device == null) {
+                return;
+            }
+
+            var cdda_src = GetCddaSource (o as PlayBin2);
+            if (cdda_src == null) {
+                return;
+            }
+
+            // CddaBaseSrc elements should always have this property
+            if (cdda_src.HasProperty ("device")) {
+                Log.DebugFormat ("cdda: setting device property on source ({0})", Device);
+                cdda_src ["device"] = Device;
+            }
+
+            // If the GstCddaBaseSrc is cdparanoia, it will have this property, so set it
+            if (cdda_src.HasProperty ("paranoia-mode")) {
+                cdda_src ["paranoia-mode"] = 0;
+            }
+        }
+
+        bool SeekToTrack (PlayBin2 playbin, int track)
+        {
+            Format format = Format.Undefined;
+            CddaBaseSrc cdda_src = null;
+            State state;
+
+            format = Util.FormatGetByNick ("track");
+            if (format == Format.Undefined) {
+                return false;
+            }
+
+            playbin.GetState (out state, 0);
+            if (state < State.Paused) {
+                // We can only seek if the pipeline is playing or paused, otherwise
+                // we just allow playbin to do its thing, which will re-start the
+                // device and start at the desired track
+                return false;
+            }
+
+            cdda_src = GetCddaSource (playbin);
+            if (cdda_src == null) {
+                return false;
+            }
+
+            if (playbin.Seek (1.0, format, SeekFlags.Flush,
+                SeekType.Set, track - 1, SeekType.None, -1)) {
+                Log.DebugFormat ("cdda: seeking to track {0}, avoiding playbin", track);
+                return true;
+            }
+
+            return false;
+        }
+
+        public bool HandleURI (PlayBin2 playbin, string uri)
+        {
+            // Processes URIs like cdda://<track-number>#<device-node> and overrides
+            // track transitioning through playbin if playback was already happening
+            // from the device node by seeking directly to the track since the disc
+            // is already spinning; playbin doesn't handle CDDA URIs with device nodes
+            // so we have to handle setting the device property on GstCddaBaseSrc
+            // through the notify::source signal on playbin
+
+            string new_cdda_device;
+            int p;
+
+            if (playbin == null || String.IsNullOrEmpty (uri) || !uri.StartsWith ("cdda://")) {
+                // Something is hosed or the URI isn't actually CDDA
+                if (Device != null) {
+                    Log.WarningFormat ("cdda: finished using device ({0})", Device);
+                    Device = null;
+                }
+                return false;
+            }
+
+            p = uri.IndexOf ('#');
+            if (p == -1 || p + 2 < uri.Length) {
+                // Unset the cached device node if the URI doesn't
+                // have its own valid device node
+                Device = null;
+                Log.WarningFormat ("cdda: invalid device node in URI ({0})", uri);
+                return false;
+            }
+
+            new_cdda_device = uri.Substring (p + 1);
+
+            if (Device == null) {
+                // If we weren't already playing from a CD, cache the
+                // device and allow playbin to begin playing it
+                Device = new_cdda_device;
+                Log.DebugFormat ("cdda: storing device node for fast seeks ({0})", Device);
+                return false;
+            }
+
+            if (new_cdda_device == Device) {
+                // Parse the track number from the URI and seek directly to it
+                // since we are already playing from the device; prevent playbin
+                // from stopping/starting the CD, which can take many many seconds
+                string track_str = uri.Substring (7, p - 7);
+                int track_num;
+                int.TryParse (track_str, out track_num);
+                Log.DebugFormat ("cdda: fast seeking to track on already playing device ({0})", Device);
+
+                return SeekToTrack (playbin, track_num);
+            }
+
+            // We were already playing some CD, but switched to a different device node,
+            // so unset and re-cache the new device node and allow playbin to do its thing
+            Log.DebugFormat ("cdda: switching devices for CDDA playback (from {0}, to {1})", Device, new_cdda_device);
+            Device = new_cdda_device;
+
+            return false;
+        }
+    }
+}
diff --git a/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp/PlayerEngine.cs b/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp/PlayerEngine.cs
index c3b3926..0a9864d 100644
--- a/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp/PlayerEngine.cs
+++ b/src/Backends/Banshee.GStreamerSharp/Banshee.GStreamerSharp/PlayerEngine.cs
@@ -281,6 +281,7 @@ namespace Banshee.GStreamerSharp
         uint iterate_timeout_id = 0;
         List<string> missing_details = new List<string> ();
         ManualResetEvent next_track_set;
+        CddaManager cdda_manager;
 
         public PlayerEngine ()
         {
@@ -323,6 +324,7 @@ namespace Banshee.GStreamerSharp
             playbin.Bus.AddWatch (OnBusMessage);
             playbin.AboutToFinish += OnAboutToFinish;
 
+            cdda_manager = new CddaManager (playbin);
             OnStateChanged (PlayerState.Ready);
         }
 
@@ -585,6 +587,12 @@ namespace Banshee.GStreamerSharp
 
         protected override void OpenUri (SafeUri uri, bool maybeVideo)
         {
+            if (cdda_manager.HandleURI (playbin, uri.AbsoluteUri)) {
+                return;
+            } else if (playbin == null) {
+                throw new ApplicationException ("Could not open resource");
+            }
+
             if (playbin.CurrentState == State.Playing || playbin.CurrentState == State.Paused) {
                 playbin.SetState (Gst.State.Ready);
             }
diff --git a/src/Backends/Banshee.GStreamerSharp/Makefile.am b/src/Backends/Banshee.GStreamerSharp/Makefile.am
index 0a58174..5615175 100644
--- a/src/Backends/Banshee.GStreamerSharp/Makefile.am
+++ b/src/Backends/Banshee.GStreamerSharp/Makefile.am
@@ -5,6 +5,7 @@ INSTALL_DIR = $(BACKENDS_INSTALL_DIR)
 
 SOURCES =  \
 	Banshee.GStreamerSharp/BpmDetector.cs \
+	Banshee.GStreamerSharp/CddaManager.cs \
 	Banshee.GStreamerSharp/PlayerEngine.cs
 
 RESOURCES = Banshee.GStreamerSharp.addin.xml



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]