PHPShout : a shoutcast streamer in PHP: Part 4
Tagged with: [ C ] [ extension ] [ icecast ] [ PHP ] [ streaming ]
In the last post, we created a template extension for our shout class. Next up, we need to do the actual implementation.
Task 6: creating setters
Let’s take a look at the source from this commit: https://github.com/jaytaph/phpshout/blob/99fed246064b5046ec18b848bf779359353268a0/shout.c
Creating the setters is just as easy as creating the getters. The same applies with the setters: we can use a generic function for setting data (we need a few, depending on the type we need to set), but it all work the same way.
Check out line 161 to 212 on the generic setters. Notice that on line 197 we are getting a long integer from PHP, but we need to store a short int. So we mask only the short in part (0xFFFF). This means we can still add a value that is higher than 65535, but it will gets converted to a short. It also would be possible to check the value, and if the value is higher than 65535, it will throw an error.
Like 215 and 216 are special cases, since they will return the error number and error string of the shout library. There are not setters for this. The rest of the functions all have a getters and setters.
Task 7: Other functionality
We’re getting REALLY close in finishing up our extension. All that is left to do is write the functionality for all the non-getter/setter functions. The first one is already there on line 263. This function returns a bool(true) when your shout object is connected to a stream, or false otherwise. You will see we are doing a mapping on line 271 so it will return either true or false.
Now, let’s take a look at all the functions added. This is done in commit: https://github.com/jaytaph/phpshout/blob/35ac2b32009936e53c3b336efed36a604d37d9f3/shout.c
First off all, I’ve changed the layout a bit for the getters and setters on line 220 to 373. The open(), close() and sync(), send() and delay() methods should look really familar by now. The same goes for the get_audio_info() and set_audio_info() methods on line 472 and line 489. The only thing you will see is that the set_audio_info() accepts 2 strings (a key and a value) from PHP. We talk about the set_metadata() function later, but the get_queue_length() function is also a simple one.
On line 613, you will see our structure filling up quite nicely with public methods now :-)
Now, the only thing left to do now is talk about the set_metadata() function. This function is a bit different than the rest, since this function actually accepts an array. Internally in the libshout library, the metadata acts like an array. So from a PHP point of view, it makes sense to use arrays for this. So what we do on line 515 is accept an array. Then on line 520, we initialize a shout_metadata structure that will hold the data we want to set.
The for-loop on line 523 to 525 can been seen as a loop over all the elements from the array we just got. Then on line 533 we call SEPARATE_ZVAL with the value for the current element. This separation actually creates a copy (but not really) of the current value so we can change it. If we leave this out, all changes to this value will also reflect back in the original PHP array, which we don’t want.
The convert_to_string makes sure that the value is always a string, which comes in handy since we need strings to store in our metadata structure.
Next on line 537, we try and get the key for the current value we are iterating. This key can either be a string or a number. If it’s a number, it means that the “str_key” value is not filled, and we will make sure that this number is converted into a string nevertheless. We do that on lines 538 to 541.
When all is done, we have a string with the key, and a string with the value (both not binary safe, but we still don’t care about that :)), and add it to our metadata structure through shout_metadata_add. The Z_STRVAL_PP is a macro that returns the string value for that current element.
When we are done with iterating, we can set the metadata on line 549, and afterwards we can free the metadata structure on line 550. We return the status code of the setting of the metadata on line 552.
And we’re done (for now)
That’s it really. All the functionality from libshout is implemented! I’ve added an example on how to use the extension on github as well https://github.com/jaytaph/phpshout/blob/35ac2b32009936e53c3b336efed36a604d37d9f3/example/example.php, but make sure you use the latest version from https://github.com/jaytaph/phpshout/.
To test if it works, I’ve done the following. On my machine, I’ve setup an icecast server (I’m running OSX, so i’ve used a trail version of nicecast, but there are others). I’ve setup the server and changed this info in the example.php configuration (primarily the ip, port and password). Then, I added a file.mp3 to the directory so there is something to stream and started the example. If everything goes ok, you see a . appearing for every 4096kb of data that is stream to the server.
Next, I connected a few listeners (they connect to http://192.168.1.10:8000/listen.m3u, in my case) and dance away to my new PHP streamer!! Oh the fun!
Conclusion
Cool things are cool, and writing something from scratch is one of them. Off course, there are hundreds better ways to stream data, but now it’s possible to do this from PHP as well. Lets stream your MP3 data, change the set_metadata according to the ID3 tags inside, show an upcoming playlist, a previous playlist, or even let people up/down vote for their favourite tunes and create a php jukebox. Who needs spotify or last.fm anymore? :p