banshee r4908 - in trunk/banshee: . src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Hardware src/Core/Banshee.Services/Banshee.MediaEngine src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage src/Dap/Banshee.Dap/Banshee.Dap src/Extensions/Banshee.AudioCd/Banshee.AudioCd
- From: abock svn gnome org
- To: svn-commits-list gnome org
- Subject: banshee r4908 - in trunk/banshee: . src/Core/Banshee.Services src/Core/Banshee.Services/Banshee.Hardware src/Core/Banshee.Services/Banshee.MediaEngine src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage src/Dap/Banshee.Dap/Banshee.Dap src/Extensions/Banshee.AudioCd/Banshee.AudioCd
- Date: Sun, 11 Jan 2009 08:16:37 +0000 (UTC)
Author: abock
Date: Sun Jan 11 08:16:37 2009
New Revision: 4908
URL: http://svn.gnome.org/viewvc/banshee?rev=4908&view=rev
Log:
2009-01-11 Aaron Bockover <abock gnome org>
This commit addresses BNC #461677, allowing device commands to be sent
to a new or existing process. Device commands allow Banshee to perform
actions against a device, such as activating the source in the UI or
starting playback of an Audio CD. Two .desktop files exist for Nautilus/GIO
to use to activate device commands on Banshee.
* src/Core/Banshee.Services/Banshee.Hardware/DeviceCommand.cs: Simple
structure that parses device action arguments such as --device-activate=x
or --device-activate-play=y
* src/Core/Banshee.Services/Banshee.Hardware/HardwareManager.cs: Provide
a DeviceCommand event which is raised whenever a DeviceCommand argument
described above is passed; this provides a simple facility for services
to listen to actions to be applied against devices (e.g. the play CD
action from Nautilus)
* src/Extensions/Banshee.AudioCd/Banshee.AudioCd/AudioCdService.cs:
Listen to the HW manager's DeviceCommand event and handle cdda actions
* src/Dap/Banshee.Dap/Banshee.Dap/DapService.cs: Listen to the HW
manager's DeviceCommand and pass them off to children DapSources at the
right time for actual handling
* src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs:
* src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs:
* src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs:
Added/implemented CanHandleDeviceCommand so the DapService can know if
a DeviceCommand action applies to the DAP
* src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs:
Fix a race where services may try to play a stream before the player
engine has entered the READY state; this happens for example when Banshee
is started with a --device-play or --device-activate-play command that
may be handled before the player engine READYs
Added:
trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/DeviceCommand.cs
Modified:
trunk/banshee/ChangeLog
trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/HardwareManager.cs
trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs
trunk/banshee/src/Core/Banshee.Services/Makefile.am
trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs
trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapService.cs
trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs
trunk/banshee/src/Extensions/Banshee.AudioCd/Banshee.AudioCd/AudioCdService.cs
Added: trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/DeviceCommand.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/DeviceCommand.cs Sun Jan 11 08:16:37 2009
@@ -0,0 +1,104 @@
+//
+// DeviceCommand.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright (C) 2009 Novell, Inc.
+//
+// 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 Banshee.Base;
+
+namespace Banshee.Hardware
+{
+ public delegate void DeviceCommandHandler (object o, DeviceCommand args);
+
+ [Flags]
+ public enum DeviceCommandAction
+ {
+ None = (0 << 0),
+ Activate = (1 << 0),
+ Play = (1 << 1)
+ }
+
+ public sealed class DeviceCommand : EventArgs
+ {
+ private DeviceCommandAction action;
+ public DeviceCommandAction Action {
+ get { return action; }
+ }
+
+ private string device_id;
+ public string DeviceId {
+ get { return device_id; }
+ }
+
+ private DeviceCommand (DeviceCommandAction action)
+ {
+ this.action = action;
+ }
+
+ internal static DeviceCommand ParseCommandLine (string command, string argument)
+ {
+ if (command == null || argument == null || !command.StartsWith ("device")) {
+ return null;
+ }
+
+ DeviceCommand d_command = null;
+
+ switch (command) {
+ case "device-activate-play":
+ d_command = new DeviceCommand (DeviceCommandAction.Activate | DeviceCommandAction.Play);
+ break;
+ case "device-activate":
+ d_command = new DeviceCommand (DeviceCommandAction.Activate);
+ break;
+ case "device-play":
+ d_command = new DeviceCommand (DeviceCommandAction.Play);
+ break;
+ case "device":
+ d_command = new DeviceCommand (DeviceCommandAction.None);
+ break;
+ default:
+ return null;
+ }
+
+ // FIXME: Should use GIO here to resolve UNIX device nodes or
+ // HAL UDIs from the GIO URI that we were likely given by Nautilus
+
+ try {
+ Banshee.Base.SafeUri uri = new Banshee.Base.SafeUri (argument);
+ d_command.device_id = uri.IsLocalPath ? uri.LocalPath : argument;
+ } catch {
+ d_command.device_id = argument;
+ }
+
+ Hyena.Log.InformationFormat ("Received device command: action = {0}, device = {1}",
+ d_command.Action, d_command.DeviceId);
+
+ return d_command;
+ }
+ }
+}
+
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/HardwareManager.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/HardwareManager.cs (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Hardware/HardwareManager.cs Sun Jan 11 08:16:37 2009
@@ -4,7 +4,7 @@
// Author:
// Aaron Bockover <abockover novell com>
//
-// Copyright (C) 2008 Novell, Inc.
+// Copyright (C) 2008-2009 Novell, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -67,6 +67,8 @@
manager.DeviceAdded += OnDeviceAdded;
manager.DeviceRemoved += OnDeviceRemoved;
+ ServiceManager.Get<DBusCommandService> ().ArgumentPushed += OnCommandLineArgument;
+
AddinManager.AddExtensionNodeHandler ("/Banshee/Platform/HardwareDeviceProvider", OnExtensionChanged);
}
@@ -79,6 +81,8 @@
manager.Dispose ();
manager = null;
}
+
+ ServiceManager.Get<DBusCommandService> ().ArgumentPushed -= OnCommandLineArgument;
if (custom_device_providers != null) {
foreach (ICustomDeviceProvider provider in custom_device_providers.Values) {
@@ -107,6 +111,62 @@
}
}
}
+
+#region Device Command Line Argument Handling
+
+ private event DeviceCommandHandler device_command;
+ public event DeviceCommandHandler DeviceCommand {
+ add {
+ try {
+ device_command += value;
+ } finally {
+ if (value != null && StartupDeviceCommand != null) {
+ value (this, StartupDeviceCommand);
+ }
+ }
+ }
+
+ remove { device_command -= value; }
+ }
+
+ private Banshee.Hardware.DeviceCommand startup_device_command;
+ private bool startup_device_command_checked = false;
+
+ public Banshee.Hardware.DeviceCommand StartupDeviceCommand {
+ get {
+ lock (this) {
+ if (startup_device_command_checked) {
+ return startup_device_command;
+ }
+
+ startup_device_command_checked = true;
+
+ foreach (KeyValuePair<string, string> argument in Banshee.Base.ApplicationContext.CommandLine.Arguments) {
+ startup_device_command = Banshee.Hardware.DeviceCommand.ParseCommandLine (argument.Key, argument.Value);
+ if (startup_device_command != null) {
+ break;
+ }
+ }
+
+ return startup_device_command;
+ }
+ }
+ }
+
+ private void OnCommandLineArgument (string argument, object value, bool isFile)
+ {
+ Banshee.Hardware.DeviceCommand command = Banshee.Hardware.DeviceCommand.ParseCommandLine (argument, value.ToString ());
+ if (command == null) {
+ return;
+ }
+
+ DeviceCommandHandler handler = device_command;
+ if (handler != null) {
+ handler (this, command);
+ }
+ }
+
+#endregion
private void OnDeviceAdded (object o, DeviceAddedArgs args)
{
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs Sun Jan 11 08:16:37 2009
@@ -53,6 +53,8 @@
private PlayerEngine active_engine;
private PlayerEngine default_engine;
private PlayerEngine pending_engine;
+ private object pending_playback_for_not_ready;
+ private bool pending_playback_for_not_ready_play;
private string preferred_engine_id = null;
@@ -183,6 +185,12 @@
}
}
}
+
+ if (pending_playback_for_not_ready != null) {
+ OpenCheck (pending_playback_for_not_ready, pending_playback_for_not_ready_play);
+ pending_playback_for_not_ready = null;
+ pending_playback_for_not_ready_play = false;
+ }
}
DBusPlayerStateHandler dbus_handler = dbus_state_changed;
@@ -272,8 +280,7 @@
}
try {
- OpenCheck (track);
- active_engine.Play ();
+ OpenCheck (track, true);
} catch (Exception e) {
Log.Exception (e);
Log.Error (Catalog.GetString ("Problem with Player Engine"), e.Message, true);
@@ -281,12 +288,18 @@
ActiveEngine = default_engine;
}
}
-
+
private void OpenCheck (object o)
{
+ OpenCheck (o, false);
+ }
+
+ private void OpenCheck (object o, bool play)
+ {
if (CurrentState == PlayerState.NotReady) {
- throw new InvalidOperationException (String.Format ("Player engine {0} is in the NotReady state",
- active_engine.GetType ().FullName));
+ pending_playback_for_not_ready = o;
+ pending_playback_for_not_ready_play = play;
+ return;
}
SafeUri uri = null;
@@ -313,6 +326,10 @@
active_engine.Open (uri);
incremented_last_played = false;
}
+
+ if (play) {
+ active_engine.Play ();
+ }
}
private bool incremented_last_played = true;
Modified: trunk/banshee/src/Core/Banshee.Services/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Makefile.am (original)
+++ trunk/banshee/src/Core/Banshee.Services/Makefile.am Sun Jan 11 08:16:37 2009
@@ -51,6 +51,7 @@
Banshee.Equalizer/EqualizerManager.cs \
Banshee.Equalizer/EqualizerSetting.cs \
Banshee.Equalizer/EqualizerSettingEvent.cs \
+ Banshee.Hardware/DeviceCommand.cs \
Banshee.Hardware/HardwareManager.cs \
Banshee.Hardware/IBlockDevice.cs \
Banshee.Hardware/ICdromDevice.cs \
Modified: trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs (original)
+++ trunk/banshee/src/Dap/Banshee.Dap.Ipod/Banshee.Dap.Ipod/IpodSource.cs Sun Jan 11 08:16:37 2009
@@ -133,6 +133,16 @@
Dispose ();
}
+ protected override bool CanHandleDeviceCommand (DeviceCommand command)
+ {
+ try {
+ SafeUri uri = new SafeUri (command.DeviceId);
+ return IpodDevice.MountPoint.StartsWith (uri.LocalPath);
+ } catch {
+ return false;
+ }
+ }
+
protected override IDeviceMediaCapabilities MediaCapabilities {
get { return ipod_device.Parent.MediaCapabilities ?? base.MediaCapabilities; }
}
Modified: trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs (original)
+++ trunk/banshee/src/Dap/Banshee.Dap.MassStorage/Banshee.Dap.MassStorage/MassStorageSource.cs Sun Jan 11 08:16:37 2009
@@ -537,6 +537,16 @@
volume.Eject ();
}
}
+
+ protected override bool CanHandleDeviceCommand (DeviceCommand command)
+ {
+ try {
+ SafeUri uri = new SafeUri (command.DeviceId);
+ return BaseDirectory.StartsWith (uri.LocalPath);
+ } catch {
+ return false;
+ }
+ }
private string GetTrackPath (TrackInfo track, string ext)
{
Modified: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapService.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapService.cs (original)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapService.cs Sun Jan 11 08:16:37 2009
@@ -47,6 +47,7 @@
public class DapService : IExtensionService, IDelayedInitializeService, IDisposable
{
private Dictionary<string, DapSource> sources;
+ private List<DeviceCommand> unhandled_device_commands;
private List<TypeExtensionNode> supported_dap_types;
private bool initialized;
private object sync = new object ();
@@ -68,6 +69,7 @@
ServiceManager.HardwareManager.DeviceAdded += OnHardwareDeviceAdded;
ServiceManager.HardwareManager.DeviceRemoved += OnHardwareDeviceRemoved;
+ ServiceManager.HardwareManager.DeviceCommand += OnDeviceCommand;
ServiceManager.SourceManager.SourceRemoved += OnSourceRemoved;
initialized = true;
}
@@ -114,6 +116,7 @@
ServiceManager.HardwareManager.DeviceAdded -= OnHardwareDeviceAdded;
ServiceManager.HardwareManager.DeviceRemoved -= OnHardwareDeviceRemoved;
+ ServiceManager.HardwareManager.DeviceCommand -= OnDeviceCommand;
ServiceManager.SourceManager.SourceRemoved -= OnSourceRemoved;
List<DapSource> dap_sources = new List<DapSource> (sources.Values);
@@ -206,6 +209,25 @@
ThreadAssist.ProxyToMain (delegate {
ServiceManager.SourceManager.AddSource (source);
source.NotifyUser ();
+
+ // If there are any queued device commands, see if they are to be
+ // handled by this new DAP (e.g. --device-activate=file:///media/disk)
+ try {
+ if (service.unhandled_device_commands != null) {
+ foreach (DeviceCommand command in service.unhandled_device_commands) {
+ if (source.CanHandleDeviceCommand (command)) {
+ service.HandleDeviceCommand (source, command.Action);
+ service.unhandled_device_commands.Remove (command);
+ if (service.unhandled_device_commands.Count == 0) {
+ service.unhandled_device_commands = null;
+ }
+ break;
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.Exception (e);
+ }
});
}
}
@@ -252,6 +274,37 @@
UnmapDevice (args.DeviceUuid);
}
+
+#region DeviceCommand Handling
+
+ private void HandleDeviceCommand (DapSource source, DeviceCommandAction action)
+ {
+ if ((action & DeviceCommandAction.Activate) != 0) {
+ ServiceManager.SourceManager.SetActiveSource (source);
+ }
+ }
+
+ private void OnDeviceCommand (object o, DeviceCommand command)
+ {
+ lock (this) {
+ // Check to see if we have an already mapped disc volume that should
+ // handle this incoming command; if not, queue it for later devices
+ foreach (DapSource source in sources.Values) {
+ if (source.CanHandleDeviceCommand (command)) {
+ HandleDeviceCommand (source, command.Action);
+ return;
+ }
+ }
+
+ if (unhandled_device_commands == null) {
+ unhandled_device_commands = new List<DeviceCommand> ();
+ }
+ unhandled_device_commands.Add (command);
+ }
+ }
+
+#endregion
+
string IService.ServiceName {
get { return "DapService"; }
}
Modified: trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs
==============================================================================
--- trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs (original)
+++ trunk/banshee/src/Dap/Banshee.Dap/Banshee.Dap/DapSource.cs Sun Jan 11 08:16:37 2009
@@ -469,6 +469,11 @@
return preferred_config;
}
}
+
+ internal protected virtual bool CanHandleDeviceCommand (DeviceCommand command)
+ {
+ return false;
+ }
private string [] acceptable_mimetypes;
public string [] AcceptableMimeTypes {
Modified: trunk/banshee/src/Extensions/Banshee.AudioCd/Banshee.AudioCd/AudioCdService.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.AudioCd/Banshee.AudioCd/AudioCdService.cs (original)
+++ trunk/banshee/src/Extensions/Banshee.AudioCd/Banshee.AudioCd/AudioCdService.cs Sun Jan 11 08:16:37 2009
@@ -43,6 +43,7 @@
public class AudioCdService : IExtensionService, IDisposable
{
private Dictionary<string, AudioCdSource> sources;
+ private List<DeviceCommand> unhandled_device_commands;
private Page pref_page;
private Section pref_section;
private uint global_interface_id;
@@ -64,6 +65,7 @@
ServiceManager.HardwareManager.DeviceAdded += OnHardwareDeviceAdded;
ServiceManager.HardwareManager.DeviceRemoved += OnHardwareDeviceRemoved;
+ ServiceManager.HardwareManager.DeviceCommand += OnDeviceCommand;
SetupActions ();
}
@@ -76,6 +78,7 @@
ServiceManager.HardwareManager.DeviceAdded -= OnHardwareDeviceAdded;
ServiceManager.HardwareManager.DeviceRemoved -= OnHardwareDeviceRemoved;
+ ServiceManager.HardwareManager.DeviceCommand -= OnDeviceCommand;
foreach (AudioCdSource source in sources.Values) {
source.Dispose ();
@@ -107,6 +110,26 @@
AudioCdSource source = new AudioCdSource (this, new AudioCdDiscModel (volume));
sources.Add (volume.Uuid, source);
ServiceManager.SourceManager.AddSource (source);
+
+ // If there are any queued device commands, see if they are to be
+ // handled by this new volume (e.g. --device-activate-play=cdda://sr0/)
+ try {
+ if (unhandled_device_commands != null) {
+ foreach (DeviceCommand command in unhandled_device_commands) {
+ if (DeviceCommandMatchesSource (source, command)) {
+ HandleDeviceCommand (source, command.Action);
+ unhandled_device_commands.Remove (command);
+ if (unhandled_device_commands.Count == 0) {
+ unhandled_device_commands = null;
+ }
+ break;
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.Exception (e);
+ }
+
Log.DebugFormat ("Mapping audio CD ({0})", volume.Uuid);
}
}
@@ -142,6 +165,59 @@
}
}
+#region DeviceCommand Handling
+
+ private bool DeviceCommandMatchesSource (AudioCdSource source, DeviceCommand command)
+ {
+ if (command.DeviceId.StartsWith ("cdda:")) {
+ try {
+ Uri uri = new Uri (command.DeviceId);
+ string match_device_node = String.Format ("{0}{1}", uri.Host,
+ uri.AbsolutePath).TrimEnd ('/', '\\');
+ string device_node = source.DiscModel.Volume.DeviceNode;
+ return device_node.EndsWith (match_device_node);
+ } catch {
+ }
+ }
+
+ return false;
+ }
+
+ private void HandleDeviceCommand (AudioCdSource source, DeviceCommandAction action)
+ {
+ if ((action & DeviceCommandAction.Activate) != 0) {
+ ServiceManager.SourceManager.SetActiveSource (source);
+ }
+
+ if ((action & DeviceCommandAction.Play) != 0) {
+ ServiceManager.PlaybackController.NextSource = source;
+ if (!ServiceManager.PlayerEngine.IsPlaying ()) {
+ ServiceManager.PlaybackController.Next ();
+ }
+ }
+ }
+
+ private void OnDeviceCommand (object o, DeviceCommand command)
+ {
+ lock (this) {
+ // Check to see if we have an already mapped disc volume that should
+ // handle this incoming command; if not, queue it for later discs
+ foreach (AudioCdSource source in sources.Values) {
+ if (DeviceCommandMatchesSource (source, command)) {
+ HandleDeviceCommand (source, command.Action);
+ return;
+ }
+ }
+
+ if (unhandled_device_commands == null) {
+ unhandled_device_commands = new List<DeviceCommand> ();
+ }
+ unhandled_device_commands.Add (command);
+ }
+ }
+
+#endregion
+
#region Preferences
private void InstallPreferences ()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]