[Python-checkins] cpython: Closes #11620: Fix support for SND_MEMORY in winsound.PlaySound.

zach.ware python-checkins at python.org
Mon Sep 5 17:32:10 EDT 2016


https://hg.python.org/cpython/rev/8fa615a2a896
changeset:   103066:8fa615a2a896
user:        Zachary Ware <zachary.ware at gmail.com>
date:        Mon Sep 05 16:31:21 2016 -0500
summary:
  Closes #11620: Fix support for SND_MEMORY in winsound.PlaySound.

Based on a patch by Tim Lesher.

files:
  Doc/library/winsound.rst  |   5 +-
  Lib/test/test_winsound.py |  16 +++++++++
  Misc/NEWS                 |   3 +
  PC/clinic/winsound.c.h    |   8 ++--
  PC/winsound.c             |  47 +++++++++++++++++++++-----
  5 files changed, 63 insertions(+), 16 deletions(-)


diff --git a/Doc/library/winsound.rst b/Doc/library/winsound.rst
--- a/Doc/library/winsound.rst
+++ b/Doc/library/winsound.rst
@@ -25,7 +25,8 @@
 .. function:: PlaySound(sound, flags)
 
    Call the underlying :c:func:`PlaySound` function from the Platform API.  The
-   *sound* parameter may be a filename, audio data as a string, or ``None``.  Its
+   *sound* parameter may be a filename, a system sound alias, audio data as a
+   :term:`bytes-like object`, or ``None``.  Its
    interpretation depends on the value of *flags*, which can be a bitwise ORed
    combination of the constants described below. If the *sound* parameter is
    ``None``, any currently playing waveform sound is stopped. If the system
@@ -92,7 +93,7 @@
 .. data:: SND_MEMORY
 
    The *sound* parameter to :func:`PlaySound` is a memory image of a WAV file, as a
-   string.
+   :term:`bytes-like object`.
 
    .. note::
 
diff --git a/Lib/test/test_winsound.py b/Lib/test/test_winsound.py
--- a/Lib/test/test_winsound.py
+++ b/Lib/test/test_winsound.py
@@ -87,6 +87,22 @@
             winsound.PlaySound,
             "none", winsound.SND_ASYNC | winsound.SND_MEMORY
         )
+        self.assertRaises(TypeError, winsound.PlaySound, b"bad", 0)
+        self.assertRaises(TypeError, winsound.PlaySound, "bad",
+                          winsound.SND_MEMORY)
+        self.assertRaises(TypeError, winsound.PlaySound, 1, 0)
+
+    def test_snd_memory(self):
+        with open(support.findfile('pluck-pcm8.wav',
+                                   subdir='audiodata'), 'rb') as f:
+            audio_data = f.read()
+        safe_PlaySound(audio_data, winsound.SND_MEMORY)
+        audio_data = bytearray(audio_data)
+        safe_PlaySound(audio_data, winsound.SND_MEMORY)
+
+    def test_snd_filename(self):
+        fn = support.findfile('pluck-pcm8.wav', subdir='audiodata')
+        safe_PlaySound(fn, winsound.SND_FILENAME | winsound.SND_NODEFAULT)
 
     def test_aliases(self):
         aliases = [
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -75,6 +75,9 @@
 Library
 -------
 
+- Issue #11620: Fix support for SND_MEMORY in winsound.PlaySound.  Based on a
+  patch by Tim Lesher.
+
 - Issue #11734: Add support for IEEE 754 half-precision floats to the
   struct module. Based on a patch by Eli Stevens.
 
diff --git a/PC/clinic/winsound.c.h b/PC/clinic/winsound.c.h
--- a/PC/clinic/winsound.c.h
+++ b/PC/clinic/winsound.c.h
@@ -17,16 +17,16 @@
     {"PlaySound", (PyCFunction)winsound_PlaySound, METH_VARARGS, winsound_PlaySound__doc__},
 
 static PyObject *
-winsound_PlaySound_impl(PyObject *module, Py_UNICODE *sound, int flags);
+winsound_PlaySound_impl(PyObject *module, PyObject *sound, int flags);
 
 static PyObject *
 winsound_PlaySound(PyObject *module, PyObject *args)
 {
     PyObject *return_value = NULL;
-    Py_UNICODE *sound;
+    PyObject *sound;
     int flags;
 
-    if (!PyArg_ParseTuple(args, "Zi:PlaySound",
+    if (!PyArg_ParseTuple(args, "Oi:PlaySound",
         &sound, &flags)) {
         goto exit;
     }
@@ -100,4 +100,4 @@
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=1044b2adf3c67014 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=b999334e2e444ad2 input=a9049054013a1b77]*/
diff --git a/PC/winsound.c b/PC/winsound.c
--- a/PC/winsound.c
+++ b/PC/winsound.c
@@ -64,7 +64,7 @@
 /*[clinic input]
 winsound.PlaySound
 
-    sound: Py_UNICODE(accept={str, NoneType})
+    sound: object
         The sound to play; a filename, data, or None.
     flags: int
         Flag values, ored together.  See module documentation.
@@ -74,22 +74,49 @@
 [clinic start generated code]*/
 
 static PyObject *
-winsound_PlaySound_impl(PyObject *module, Py_UNICODE *sound, int flags)
-/*[clinic end generated code: output=ec24b3a2b4368378 input=3411b1b7c1f36d93]*/
+winsound_PlaySound_impl(PyObject *module, PyObject *sound, int flags)
+/*[clinic end generated code: output=49a0fd16a372ebeb input=7bdf637f10201d37]*/
 {
     int ok;
+    wchar_t *wsound;
+    Py_buffer view = {NULL, NULL};
 
-    if (flags & SND_ASYNC && flags & SND_MEMORY) {
-        /* Sidestep reference counting headache; unfortunately this also
-            prevent SND_LOOP from memory. */
-        PyErr_SetString(PyExc_RuntimeError,
-                        "Cannot play asynchronously from memory");
-        return NULL;
+    if (sound == Py_None) {
+        wsound = NULL;
+    } else if (flags & SND_MEMORY) {
+        if (flags & SND_ASYNC) {
+            /* Sidestep reference counting headache; unfortunately this also
+                prevent SND_LOOP from memory. */
+            PyErr_SetString(PyExc_RuntimeError,
+                            "Cannot play asynchronously from memory");
+            return NULL;
+        }
+        if (PyObject_GetBuffer(sound, &view, PyBUF_SIMPLE) < 0) {
+            return NULL;
+        }
+        wsound = (wchar_t *)view.buf;
+    } else {
+        if (!PyUnicode_Check(sound)) {
+            PyErr_Format(PyExc_TypeError,
+                         "'sound' must be str or None, not '%s'",
+                         Py_TYPE(sound)->tp_name);
+            return NULL;
+        }
+        wsound = PyUnicode_AsWideCharString(sound, NULL);
+        if (wsound == NULL) {
+            return NULL;
+        }
     }
 
+
     Py_BEGIN_ALLOW_THREADS
-    ok = PlaySoundW(sound, NULL, flags);
+    ok = PlaySoundW(wsound, NULL, flags);
     Py_END_ALLOW_THREADS
+    if (view.obj) {
+        PyBuffer_Release(&view);
+    } else if (sound != Py_None) {
+        PyMem_Free(wsound);
+    }
     if (!ok) {
         PyErr_SetString(PyExc_RuntimeError, "Failed to play sound");
         return NULL;

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list