Most Computer users are familiar with the Sounds that Windows emits when you plug and unplug a USB thumb drive. It’s a useful form of auditory feedback that the drive was in fact detected. However, I’ve found linux to be oddly tacit in this regard. So I set to work writing a python script that uses DBUS to monitor for new USB devices and will play a sound whenever a new Volume is attached.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
#!/usr/bin/python #by BC_Programming import dbus import gobject import time import subprocess print "BASeCamp 'USBSounds' Simple USB Volume notification sound." #playsound merely shells out to mplayer. I would have preferred an integrated solution but... meh. def playsound(soundfile): subprocess.call(["mplayer", "hardwareinsert.wav"], stdout=open('/dev/null', 'w'), stderr=open('/dev/null', 'w')) class DeviceAddedListener: def __init__(self): #get the system bus... self.bus = dbus.SystemBus() #get the manager self.hal_manager_obj = self.bus.get_object( 'org.freedesktop.Hal', '/org/freedesktop/Hal/Manager') #get the interface for the manager self.hal_manager = dbus.Interface(self.hal_manager_obj,'org.freedesktop.Hal.Manager') #connect to the appropriate signals. self.hal_manager.connect_to_signal('DeviceAdded', self._filteradd) self.hal_manager.connect_to_signal("DeviceRemoved",self._filterremove) #note: I couldn't get DeviceRemoval sounds to work since it doesn't let you #inspect whether the removed device is a volume via "QueryCapability"... since it's gone. def _filteradd(self, udi): device_obj = self.bus.get_object ('org.freedesktop.Hal', udi) device = dbus.Interface(device_obj, 'org.freedesktop.Hal.Device') #if it is a volume, call the do_add function... if device.QueryCapability("volume"): return self.do_add(device) def _filterremove(self,udi): try: #device_obj = self.bus.get_object('org.freedesktop.Hal',udi) #device = dbus.Interface(device_obj,'org.freedesktop.Hal.Device') #if device.QueryCapability("volume"): # return self.do_remove(device) except: return #unused.... def do_remove(self,volume): playsound("hardwareremove.wav") #displays some info about the added device to the console (maybe future changes can pop stuff like volume label, device file, size, etc into a Notification box?) def do_add(self, volume): device_file = volume.GetProperty("block.device") label = volume.GetProperty("volume.label") fstype = volume.GetProperty("volume.fstype") mounted = volume.GetProperty("volume.is_mounted") mount_point = volume.GetProperty("volume.mount_point") try: size = volume.GetProperty("volume.size") except: size = 0 print "New storage device detected:" print " device_file: %s" % device_file print " label: %s" % label print " fstype: %s" % fstype if mounted: print " mount_point: %s" % mount_point else: print " not mounted" print " size: %s (%.2fGB)" % (size, float(size) / 1024**3) #and play a sound. playsound("hardwareinsert.wav") #main loop... if __name__ == '__main__': from dbus.mainloop.glib import DBusGMainLoop DBusGMainLoop(set_as_default=True) loop = gobject.MainLoop() print "in __main__..." DeviceAddedListener() loop.run() |
As can be seen, it’s a tad messy, and even rather hackish. For one thing, it uses DBUS, which to my understanding is deprecated. Unfortunately, the replacement I couldn’t really get a clear answer on. From what I can gather, the proper method for now is libnotify and pynotify, but I couldn’t get libnotify to compile and thus was not able to properly use pynotify, and I didn’t want to have to force people to go through that sort of hell when they tried to use my script, so I stuck to DBUS.
The only limitation I discovered is that on device removal, you can’t really inspect what device was removed. At first I just figured, Just play the sound everytime and let the user figure it out, but for some reason that just assaulted me with constant device removal sounds. So I ended up commenting (and I think removing) that particular segment of code.
Playing Sounds is unnecessarily difficult in Python, or more specifically, Linux. It’s ridiculous. First I found a build in module for python, ossdevsound (or something to that effect), but attempts to use that failed because apparently it uses OSS, which apparently was replaced by ALSA for whatever reason. So I tried pygame, which errored out that I had no mixer device when I tried to initialize the mixer. So I decided to hell with it and just spawned a mplayer process, and redirected it’s stdout to NULL to avoid the nasty business where it barfs all over the console. And amazingly, that seems to work fine for device insertions, which I decided I was content with.
By default I use the Windows insertion and removal sound files. The removal sound isn’t actually used but I kept it in the g-zipped tar because I wanted to. Personally I usually just launch this in a terminal and then tuck it away on another desktop. No doubt one can execute it as a daemon or something instead and get the functionality without the console window baggage to keep around, though.
Have something to say about this post? Comment!