PHPShout : a shoutcast streamer in PHP: Part 1
Tagged with: [ C ] [ extension ] [ icecast ] [ PHP ] [ streaming ]
To continue our journey in pointless, but nevertheless fun things to create, I’ve created a simple PHP extension that allows you stream music data to an IceCast server in pure PHP. For this I’m using the libshout3 library which can stream both MP3 or OGG/Vorbis data to multiple stream servers (including IceCast, ShoutCast etc). In this blog-post I will try to explain how I’ve created this extension, and off course, how you can use it.
Task 1: download and read up the specs
There are two ways to create such a system. The first way is to create a 100% pure PHP class and the second one by creating a wrapper-extension for an existing (C) library. The biggest advantage of writing a PHP class is that you don’t need to compile a new extension, but a big drawback is that you are implementing things in PHP that are already implemented in the C library. Furthermore, the PHP class will never be as fast as the C library. The drawback of writing an extension, is - well - you need to know a bit about C and the PHP toolkit with all the macro’s and quirks which might not be easy. However, you don’t need to duplicate functionality and nowadays compiling and installing an extension is pretty much automated.
So an extension it is, but before we can actually write the extension, we need to know how we would call the functionality from a PHP point of view. Do we create procedural function, should we create an OO interface? Or maybe even multiple interfaces? For this we need to know how the library works in C, which takes a bit of reading up. But luckily, there are some good documents for the library we are using: http://www.aelius.com/njh/libshout-doc/libshout.html and the actual libshout download has got some examples on how to use it.
The library itself is easy enough to install from a debian / ubuntu system, so I’d reckon CentOS would not be any different although I haven’t checked. A mere “apt-get install libshout3-dev” will do the trick in order to install the development files and the library itself. It’s not enough to get only the library, since we need to have the include files (*.h) files as well.
Task 2: create skeleton extension
Now for the fun part. I’ve decided to create a sort-of OO interface. Actually it’s has got not much to do with OO, but merely it’s a class that wraps our functionality. Might as well be a separate namespace, but this way it makes it easier to extend our class if you need to. Now, on to the actual creation of the extension. What I did was create a skeleton extension first. This skeleton holds not much info, but it’s easy to start from here.
You can find this at my GitHub commit: https://github.com/jaytaph/phpshout/tree/0fc0fe0fe3eb426591987194deff8bdecb717d34
This is pretty much the bare minimum for an (OO) extension. The most important files being config.m4 and shout.c.
config.m4:
If you are not using external libraries, your config.m4 doesn’t have to be this complex. This configuration “template” will be used to generate a configure script which in it’s turn creates a makefile to compile the actual extension. I’ve blogged about these configuration tools in another blog post here and there are still some in draft which I will release (very soon, I promise!). This config.m4 gives your ./configure script an option called “-with-shout”, where you can actually add the path to your shout.h include files. If you don’t specify it, it will check for /usr and /usr/local, but in case it’s somewhere else, you can easily specify it. That is basically what lines 5 to 25 do.
If this is found, lines 27 to 40 will check for the actual library called libshout(.so). This library should be in your LD_LIBRARY_PATH, which 9 out of 10 time is, so you don’t have to worry about it. If the library is found, it will do a sanity check if there is a function called shout_init() is defined. If so, we will assume you have to correct library. If not, it might be another libshout (either version, or maybe a complete other library).
shout.c:
Config.m4 should always be named config.m4, but shout.c is just the name of the extension, and might as well be named differently. For instance, when you have a “rainbow” extension (whatever that might be), the name of the main source file might be rainbow.c. Off course, your extension might need multiple source files (rainbow-pony.c, rainbow-unicorn.c etc), so you must add them to your config.m4 as well (on line 42).
Even though this file looks very complicated, it really isn’t. Line 34 includes the shout library include file. This allows us to use the shout functions. Because we searched for this include file through the config.m4 and the configure script, the makefile automatically knows where this file is located so we don’t have to worry about it anymore. Line 38-40 defines an internal structure that holds all information for a single PHP shout-object, sometimes called the “object store”. So when we have 2 objects in PHP, we have two php_shout_obj structures or “stores”. For now, this only include the actual object information (the zend_object value), but later on we can fill it with internal data. You can see this a bit of the private values of our class if that makes sense to you.
Next up are some (static) functions for creating, freeing, and cloning our objects. These are standard boilerplate stuff. For instance the shout_object_free() function does nothing more than destroying our internal object through a zend_object_std_dtor() call, and free()’ing our store.
The shout_object_new_ex() and shout_object_new() are functions to create a new object store. The shout_object_new is nothing more than a redirect to shout_object_new_ex(). Lines 68 and 69 initializes some memory for our internal php_shout_object structure and clearing this memory. lines 75 and 76 initializes the internal zend_object in our structure with the default properties.
Lines 78 and 79 will set the handlers (functions) for this object, basically which function it will need to call when the object will be freed and the basic handlers (which are saved in shout_object_handlers, we set these values later). After that, we must return a zend_object_value object with this information.
Line 91 to 101 will deal with cloning an object. This function gets the old object store, creates a new object store (line 94) and line 96 copies/duplicate the actual zend_object data that is located in our store. If there is any other internal data in our store, we need to make sure we duplicate or copy this over. But since we don’t have anything stored yet, we skip this part for now.
Those are the house-keeping functions, but somehow this all must be connected together. This is where the next functions are structure come in. On line 105, we define a structure that holds all the functions as seen from our PHP class. You can see, we don’t have any and that’s ok, since this is a template.
Next up on line 112, the PHP_MINIT_FUNCTION. This is a macro (as you will see a lot in the PHP core and extensions), which defines a module initialization function for the “shout” extension. This function will copy the standard handlers that php uses into it’s own shout_object_handlers (line 117). This way, when we want handle something differently in our own shout-classes, we can easily do so. Remember that these handlers are copied over every time we create a new object (line 79).
The next lines - 122 creates a new class entry with our functions (which we don’t have yet). Line 123 tells it that we need to use shout_object_new() function in order to create new objects and line 124 sets our clone() handler to be our own customized clone-handler. Line 126 actually registers our class and we get our own shout class entry back which we save for later usage.
Lines 134 to 140 is a function that will define the information that is shown during php’s phpinfo(). This will print a table that shout support is enabled (obviously, otherwise this whole table would not be present), plus the version of our php extension plus the version of the library we are using (you see here we are using our first call to the actual shout library!).
Now, in order to connect all this together to PHP can actually use it, we have to create a zend_module_entry structure on line 144. It consists of standard module headers (STANDARD_MODULE_HEADER, the name of the extension (shout), the functions used (shout_funcs), our module startup function that will be run ONCE the extension is loaded, the module shutdown function that will be run ONCE the extension is unloaded (in our case, we haven’t defined any, so this is NULL). The next two NULL values are the functions loaded every time a request is made. Then the function that returns the information for phpinfo(), and last the version of our module, plus some module properties.
TSRMLS_CC?
On occasion, you will see argument lists ended with TSRMLS_CC
. If you don’t know PHP, these doesn’t make any sense,
since they are there for thread-safety. For more information about it, take a look at the excellent post about PHP and
thread safety: http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html
Next, up, we need to implement functionality.