Attached is a patch against shout-python-0.2 which does two trivial but very useful things (1) The function "get_connected" is exported so that shout-python becomes usable in nonblocking mode. In the current version of shout-python "open" raises an exception in nonblocking mode. (2) The global interpreter lock is released in the potentially blocking functions "open", "send" and "sync". In this way a shout-python can run in blocking mode in a separate thread without blocking other threads. Both parts were tested. I needed either (1) or (2) to make a webgui for controlling an icecast source. I tried both approaches. They both work but in the end I opted for (2) since the code was cleaner. Regards, Michel -------------- next part -------------- A non-text attachment was scrubbed... Name: shout-python_0.2-1.diff Type: text/x-diff Size: 2622 bytes Desc: not available Url : http://lists.xiph.org/pipermail/icecast-dev/attachments/20080830/b50c2ca6/attachment.diff
Thanks! I've been an absentee maintainer, but I'll try to get my svn access in working order again tomorrow. The patch looks good from here. On Saturday, 30 August 2008 at 16:00, Michel Van den Bergh wrote:> Attached is a patch against shout-python-0.2 which does two trivial but > very useful things > > (1) The function "get_connected" is exported so that shout-python becomes > usable > in nonblocking mode. In the current version of shout-python "open" > raises an exception in nonblocking mode. > > (2) The global interpreter lock is released in the potentially blocking > functions "open", "send" and "sync". In this way a shout-python can run > in blocking mode > in a separate thread without blocking other threads. > > Both parts were tested. > > I needed either (1) or (2) to make a webgui for controlling an icecast > source. I tried both approaches. They both work but in the end I opted for > (2) since the code was cleaner. > > Regards, > Michel > > >> --- shout-python-0.2.orig/shout.c > +++ shout-python-0.2/shout.c > @@ -57,6 +57,7 @@ > > static PyObject* pshoutobj_open(ShoutObject* self); > static PyObject* pshoutobj_close(ShoutObject* self); > +static PyObject* pshoutobj_get_connected(ShoutObject* self); > static PyObject* pshoutobj_send(ShoutObject* self, PyObject* args); > static PyObject* pshoutobj_sync(ShoutObject* self); > static PyObject* pshoutobj_delay(ShoutObject* self); > @@ -81,6 +82,7 @@ > "\"host\", \"port\", \"password\" and \"mount\" must be specified).\n\n" > "Methods:\n" > " open() - connect to server\n" > + " get_connected() - monitor connection status in nonblocking mode\n" > " close() - disconnect from server\n" > " send(data) - send audio data to server\n" > " sync() - sleep until server needs more data. This is equal to\n" > @@ -185,6 +187,8 @@ > "Connect to server." }, > { "close", (PyCFunction)pshoutobj_close, METH_NOARGS, > "Close connection to server." }, > + { "get_connected", (PyCFunction)pshoutobj_get_connected, METH_NOARGS, > + "Check for connection progress." }, > { "send", (PyCFunction)pshoutobj_send, METH_VARARGS, > "Send audio data to server." }, > { "sync", (PyCFunction)pshoutobj_sync, METH_NOARGS, > @@ -363,9 +367,14 @@ > } > > static PyObject* pshoutobj_open(ShoutObject* self) { > - if (shout_open(self->conn) != SHOUTERR_SUCCESS) { > + int ret; > + Py_BEGIN_ALLOW_THREADS > + ret=shout_open(self->conn); > + Py_END_ALLOW_THREADS > + if (!((ret == SHOUTERR_SUCCESS)|| > + ((ret==SHOUTERR_BUSY) && shout_get_nonblocking(self->conn)))) { > PyErr_SetString(ShoutError, shout_get_error(self->conn)); > - > + > return NULL; > } > > @@ -385,11 +394,15 @@ > static PyObject* pshoutobj_send(ShoutObject* self, PyObject* args) { > const unsigned char* data; > size_t len; > + int ret; > > if (!PyArg_ParseTuple(args, "s#", &data, &len)) > return NULL; > + Py_BEGIN_ALLOW_THREADS > + ret=shout_send(self->conn, data, len); > + Py_END_ALLOW_THREADS > > - if (shout_send(self->conn, data, len) != SHOUTERR_SUCCESS) { > + if (ret != SHOUTERR_SUCCESS) { > PyErr_SetString(ShoutError, shout_get_error(self->conn)); > > return NULL; > @@ -399,11 +412,17 @@ > } > > static PyObject* pshoutobj_sync(ShoutObject* self) { > + Py_BEGIN_ALLOW_THREADS > shout_sync(self->conn); > + Py_END_ALLOW_THREADS > > return Py_BuildValue("i", 1); > } > > +static PyObject* pshoutobj_get_connected(ShoutObject* self) { > + return Py_BuildValue("i", shout_get_connected(self->conn)); > +} > + > static PyObject* pshoutobj_delay(ShoutObject* self) { > return Py_BuildValue("i", shout_delay(self->conn)); > }> _______________________________________________ > Icecast-dev mailing list > Icecast-dev at xiph.org > http://lists.xiph.org/mailman/listinfo/icecast-dev
On Saturday, 30 August 2008 at 16:00, Michel Van den Bergh wrote:> Attached is a patch against shout-python-0.2 which does two trivial but > very useful things > > (1) The function "get_connected" is exported so that shout-python becomes > usable > in nonblocking mode. In the current version of shout-python "open" > raises an exception in nonblocking mode. > > (2) The global interpreter lock is released in the potentially blocking > functions "open", "send" and "sync". In this way a shout-python can run > in blocking mode > in a separate thread without blocking other threads. > > Both parts were tested. > > I needed either (1) or (2) to make a webgui for controlling an icecast > source. I tried both approaches. They both work but in the end I opted for > (2) since the code was cleaner.This is in subversion now. I'll try to get a new release out this weekend. Thanks!
>This is in subversion now. I'll try to get a new release out this >weekend. Thanks!Thanks! But I noticed that giving up the global interpretor lock in a few functions allows other threads to do something stupid (like deleting the shout object during a write). So for everything to be absolutely thread safe a python shout object should contain a mutex and there should be appropriate locking around accesses to s->conn. It is a little hard to figure out precisely at what places locking would be needed. The safest method I could think off is simply to include thread safe versions of the shout api functions which have a shout_t as its first argument. For example int shout_set_host_safe_ts(shout_t *self, char* host, pthread_mutex_t *mutex){ int ret; pthread_mutex_lock (mutex)); ret=shout_set_host(s->conn,host); pthread_mutex_unlock (mutex)); return ret; } One should then use the thread safe version instead of the original api functions. To avoid mistakes I would generate these definitions automatically from shout.h using a small python program. What do you think? Regards, Michel Brendan Cully wrote:> On Saturday, 30 August 2008 at 16:00, Michel Van den Bergh wrote: > >> Attached is a patch against shout-python-0.2 which does two trivial but >> very useful things >> >> (1) The function "get_connected" is exported so that shout-python becomes >> usable >> in nonblocking mode. In the current version of shout-python "open" >> raises an exception in nonblocking mode. >> >> (2) The global interpreter lock is released in the potentially blocking >> functions "open", "send" and "sync". In this way a shout-python can run >> in blocking mode >> in a separate thread without blocking other threads. >> >> Both parts were tested. >> >> I needed either (1) or (2) to make a webgui for controlling an icecast >> source. I tried both approaches. They both work but in the end I opted for >> (2) since the code was cleaner. >>