Index: src/config.py
===================================================================
--- src/config.py	(revision 6346)
+++ src/config.py	(working copy)
@@ -39,6 +39,7 @@
 from common import gajim
 from common import connection
 from common import i18n
+from common import sound
 
 _ = i18n._
 APP = i18n.APP
@@ -977,7 +978,7 @@
 		if not iter:
 			return
 		snd_event_config_name = model[iter][3]
-		helpers.play_sound(snd_event_config_name)
+		sound.play_event(snd_event_config_name)
 
 	def on_open_advanced_editor_button_clicked(self, widget, data = None):
 		if gajim.interface.instances.has_key('advanced_config'):
Index: src/notify.py
===================================================================
--- src/notify.py	(revision 6346)
+++ src/notify.py	(working copy)
@@ -25,6 +25,7 @@
 from common import gajim
 from common import i18n
 from common import helpers
+from common import sound
 i18n.init()
 _ = i18n._
 
@@ -115,7 +116,7 @@
 			else:
 				print 'Event not implemeted yet'
 	if (do_sound):
-		helpers.play_sound(event)	
+		sound.play_event(event)	
 	 
 
 def popup(event_type, jid, account, msg_type = '', path_to_image = None,
Index: src/gajim.py
===================================================================
--- src/gajim.py	(revision 6346)
+++ src/gajim.py	(working copy)
@@ -39,6 +39,7 @@
 
 from common import exceptions
 from common import i18n
+from common import sound
 i18n.init()
 _ = i18n._
 
@@ -515,10 +516,10 @@
 
 		if gajim.config.get_per('soundevents', 'first_message_received',
 			'enabled') and first:
-			helpers.play_sound('first_message_received')
+			sound.play_event('first_message_received')
 		elif gajim.config.get_per('soundevents', 'next_message_received',
 			'enabled'):
-			helpers.play_sound('next_message_received')
+			sound.play_event('next_message_received')
 
 		if pm:
 			room_jid = jid
@@ -617,7 +618,7 @@
 		msg = array[1]
 		# do not play sound when standalone chatstate message (eg no msg)
 		if msg and gajim.config.get_per('soundevents', 'message_sent', 'enabled'):
-			helpers.play_sound('message_sent')
+			sound.play_event('message_sent')
 		
 	def handle_event_subscribe(self, account, array):
 		#('SUBSCRIBE', account, (jid, text))
Index: src/groupchat_control.py
===================================================================
--- src/groupchat_control.py	(revision 6346)
+++ src/groupchat_control.py	(working copy)
@@ -36,6 +36,7 @@
 
 from common import gajim
 from common import helpers
+from common import sound
 
 from chat_control import ChatControl
 from chat_control import ChatControlBase
@@ -542,9 +543,9 @@
 				other_tags_for_name.append('bold')
 				other_tags_for_text.append('marked')
 			if sound == 'received':
-				helpers.play_sound('muc_message_received')
+				sound.play_event('muc_message_received')
 			elif sound == 'highlight':
-				helpers.play_sound('muc_message_highlight')
+				sound.play_event('muc_message_highlight')
 
 			self.check_and_possibly_add_focus_out_line()
 
Index: src/common/sound.py
===================================================================
--- src/common/sound.py	(revision 0)
+++ src/common/sound.py	(revision 0)
@@ -0,0 +1,147 @@
+##	common/gst.py
+##
+## Contributors for this file:
+##	- Sami Haahtinen <ressu@ressukka.net>
+##
+## Copyright (C) 2006 Sami Haahtinen <ressu@ressukka.net>
+##
+## 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; version 2 only.
+##
+## 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.
+
+import gajim
+import os
+
+class GajimPlayer:
+  player = None
+
+  def __init__(self):
+    # For now, lets default to GStreamer, winsound, and then try External player
+    # FIXME: This really needs elegance!
+    if not gajim.config.get('sounds_on'):
+      raise NoSound
+      
+    try:
+      self.player = GajimGstPlayer()
+    except self.PlayerUnavailable:
+      try:
+        self.player = GajimWin32Player()
+      except self.PlayerUnavailable:
+        try:
+          self.player = GajimExtPlayer()
+        except self.PlayerUnavailable:
+          self.player = None # Make sure that player is still set to None
+          raise NoSound
+
+  class NoSound(Exception):
+    '''Notifies the system that we should be silent'''
+
+  class BeepOnly(Exception):
+    '''Notifies the system that we should just beep'''
+  
+  class PlayerUnavailable(Exception):
+    '''Notifies that the player is unavailable'''
+
+  def event_to_soundfile(self, event):
+    '''Returns the full file path for sound file of an event'''
+    # Check if we should play sound at all
+    if self.player is None:
+      raise NoSound
+
+    # Get soundevent
+    path_to_soundfile = gajim.config.get_per('soundevents', event, 'path')
+    
+    if path_to_soundfile is None or not os.path.exists(path_to_soundfile):
+      raise NoSound
+
+    return path_to_soundfile
+
+  def play(self, soundfile):
+    if soundfile == 'beep':
+      beep()
+    
+    if self.player is None:
+      return
+    
+    self.player.play_sound(soundfile)
+
+  def beep(self):
+    '''Play a single beep'''
+    # FIXME: There must be a better way
+    print "\a"
+
+# FIXME: This class hasn't gotten any testing!
+class GajimWin32Player:
+  '''User native Win32 layer to play sounds'''
+
+  def __init__(self):
+    try:
+      import winsound
+    except ImportError:
+      # gst module is not available...
+      raise GajimPlayer.PlayerUnavailable, "Winsound library not available"
+  
+  def play_sound(self,soundfile):
+    try:
+      winsound.PlaySound(soundfile, winsound.SND_FILENAME|winsound.SND_ASYNC)
+    except:
+      pass
+
+class GajimExtPlayer:
+  '''Use external application to play the sounds'''
+
+  def __init__(self):
+    self.player = gajim.config.get('soundplayer')
+    if self.player == '':
+      raise GajimPlayer.PlayerUnavailable, "External player not set"
+    # FIXME: We should check if the player exists!
+
+  def play_sound(self,soundfile):
+    soundfile = soundfile.replace('"', '\\"')
+    command = self.player + ' "' + soundfile + '" &'
+    os.system(command)
+
+class GajimGstPlayer:
+  '''Player that plays sound events through the GStreamer framework'''
+
+  def __init__(self):
+    try:
+      import gst
+    except ImportError:
+      # gst module is not available...
+      raise GajimPlayer.PlayerUnavailable, "Python Gstreamer modules not available"
+    self.gst = gst
+    self.GstBin = self.gst.parse_launch("playbin")
+
+    # Create a sink for video, if someone decides to use a video file ;)
+    fakesink = self.gst.element_factory_make("fakesink")
+    self.GstBin.set_property("video-sink", fakesink)
+
+  def play_sound(self,soundfile):
+    self.GstBin.set_state(self.gst.STATE_NULL)
+
+    # since playbin takes input in URI format, add file:// prefix
+    sounduri = "file://" + os.path.abspath(soundfile)
+    self.GstBin.set_property('uri', sounduri)
+    
+    self.GstBin.set_state(self.gst.STATE_PLAYING)
+
+def play_event(event):
+  global Player
+  try:
+    try:
+       soundfile = Player.event_to_soundfile(event)
+    except NameError:
+       Player = GajimPlayer()
+       soundfile = Player.event_to_soundfile(event)
+  except GajimPlayer.NoSound:
+    # No sound.
+    return
+
+  # Ok, we should be clear to play the sound
+  Player.play(soundfile)
Index: src/common/helpers.py
===================================================================
--- src/common/helpers.py	(revision 6346)
+++ src/common/helpers.py	(working copy)
@@ -30,7 +30,6 @@
 from xmpp_stringprep import nodeprep, resourceprep, nameprep
 
 try:
-	import winsound # windows-only built-in module for playing wav
 	import win32api
 	import win32con
 except:
@@ -417,31 +416,6 @@
 		except:
 			pass
 
-def play_sound(event):
-	if not gajim.config.get('sounds_on'):
-		return
-	path_to_soundfile = gajim.config.get_per('soundevents', event, 'path')
-	if path_to_soundfile == 'beep':
-		print '\a' # make a speaker beep
-		return
-	if path_to_soundfile is None or not os.path.exists(path_to_soundfile):
-		return
-	if os.name == 'nt':
-		try:
-			winsound.PlaySound(path_to_soundfile,
-				winsound.SND_FILENAME|winsound.SND_ASYNC)
-		except:
-			pass
-	elif os.name == 'posix':
-		if gajim.config.get('soundplayer') == '':
-			return
-		player = gajim.config.get('soundplayer')
-		# we add the path in "" so we have good parsing from shell
-		path_to_soundfile = path_to_soundfile.replace('"', '\\"') # escape "
-		command = player + ' "' + path_to_soundfile + '" &'
-		#FIXME: when we require 2.4+ use subprocess module
-		os.system(command)
-
 def get_file_path_from_dnd_dropped_uri(uri):
 	path = urllib.url2pathname(uri) # escape special chars
 	path = path.strip('\r\n\x00') # remove \r\n and NULL
