Source code for dragonfly.actions.action_playsound

# This file is part of Dragonfly.
# (c) Copyright 2007, 2008 by Christo Butcher
# Licensed under the LGPL.
#   Dragonfly is free software: you can redistribute it and/or modify it
#   under the terms of the GNU Lesser General Public License as published
#   by the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#   Dragonfly is distributed in the hope that it will be useful, but
#   WITHOUT ANY WARRANTY; without even the implied warranty of
#   Lesser General Public License for more details.
#   You should have received a copy of the GNU Lesser General Public
#   License along with Dragonfly.  If not, see
#   <>.

PlaySound action

The :class:`PlaySound` action class is used to play wave files.

Example usage

The following example shows how to play a wave file using the
:class:`PlaySound` action class::



On Windows, :class:`PlaySound` uses the `PlaySound Windows API function

The action can be used to play Windows system sounds. For example::

    # Play the system shutdown sound.

    # Play the logout sound.

System sound names are matched against registry keys.

Invalid file paths or unknown system sounds will result in the default error
sound being played. ``RuntimeErrors`` will be raised if Windows fails to
play a known system sound.

Other platforms

On other platforms, the :class:`PlaySound` class will use `PyAudio
<>`__ to play specified wave

Invalid file paths will result in errors on other platforms.

Class reference


# pylint: disable=E0401,C0413
# This file imports from optional or Win32-only packages depending on the
# platform.

from ctypes import CFUNCTYPE, c_char_p, c_int, cdll

import os
import wave

if == 'nt':
    import winsound

    import pyaudio
except ImportError:
    pyaudio = None

from .action_base         import ActionBase


ERROR_HANDLER_FUNC = CFUNCTYPE(None, c_char_p, c_int, c_char_p, c_int,

def _get_pa_instance():
    # Suppress initial ALSA messages if using ALSA.
    # Got this from:
        asound = cdll.LoadLibrary('')
        c_error_handler = ERROR_HANDLER_FUNC(
            lambda filename, line, function, err, fmt: None
        # We'll most likely get here if the Port Audio host API isn't ALSA.
        asound = None

    # Create the pa instance.
    pa = pyaudio.PyAudio()

    # If necessary, restore the original error handler.
    if asound:
    return pa

def _pyaudio_play(name):
    if not name:

    if pyaudio is None:
        # Raise an error because pyaudio isn't installed.
        raise RuntimeError("pyaudio must be installed to use PlaySound "
                           "on this platform")

    # Play the wave file.
    pa = _get_pa_instance()
    chunk = 1024
    wf =, 'rb')
    stream =,
                     channels=wf.getnchannels(), rate=wf.getframerate(),
    data = wf.readframes(chunk)
    while data:
        data = wf.readframes(chunk)


[docs]class PlaySound(ActionBase): """ Start playing a wave file or system sound. When this action is executed, the specified wave file or named system sound is played. Playing named system sounds is only supported on Windows. """ def __init__(self, name='', file=None): """ Constructor arguments: - *name* (*str*, default *empty string*) -- name of the Windows system sound to play. This argument is effectively an alias for *file* on other platforms. - *file* (*str*, default *None*) -- path of wave file to play when the action is executed. If *name* and *file* are both *None*, then waveform playback will be silenced on Windows when the action is executed. Nothing will happen on other platforms. """ ActionBase.__init__(self) self._flags = 0 if file is not None: self._name = file if == 'nt': self._flags = winsound.SND_FILENAME else: self._name = name if == 'nt': self._flags = winsound.SND_ALIAS # Expand ~ constructions and shell variables in the file path if # necessary. if file is not None or != 'nt': self._name = os.path.expanduser(os.path.expandvars(self._name)) self._str = str(self._name) def _execute(self, data=None): if == 'nt': # Play the file or sound using the Windows API. winsound.PlaySound(self._name, self._flags) else: # Play the file with pyaudio. _pyaudio_play(self._name)