Audio Server for Audio Sharing with Voting

Audio Server
An ECE 5725 Final Project By James Cassell


Demonstration Video


Introduction

For the project we created an audio server that queues and plays songs based on different user's popularity. Songs are played on a speaker from a queue of submitted youtube links, where they can be upvoted or downvoted by other users connected to the device. This increases or decreases a user's popularity. Users are able to register, submit links, and vote on songs via a webserver hosted on a Raspberry Pi.


Generic placeholder image

Project Objective:

  • Allow users to submit audio links to be played by the server.
  • Allow users to sign up and vote on if songs are good or not.
  • When there is a queue, sort it based on the popularity of the submitting user.

Design

The first step to create the audio server, was to have a way for the server to keep track of different users and their popularity. In order to do this, we use a database. Specifically, we used an sqlite3 database and used their C++ library to interact with it. Due to the simplicity of our system, our database has only a single table, the user table. Inside the tables we have four columns:

The database is used for keeping track of a user's popularity as well as checking the associated hash for authentication. To authenticate a user, we query the database for a user's salt and hash values. We then concatinate the user's salt and password, then take the SHA256 and compare it to the retrieved hash from the database. If the hashes are the same, the user is considered authenticated. The hash and salt in the database are generated when we register a new user to the system. We do this so that we do not need to store the plaintext password of the user. The popularity column is set to 0 upon user registration, it is then incremented or decremented upon upvoting or downvoting respectively. An image representing our database setup can be seen below with an example user.

To make interaction with the database simpler, we created a wrapper class that contains a reference to the sqlite3 database. This object then has multiple functions that will generate the SQL command and parse the results for a user, such as authenticating a user and getting their popularity.

This database object is then used by our audio server. We have an AudioServer class which contains a reference to our database object, it also contains a queue songs. The AudioServer class is in charge of adding songs to the queue, upvoting or downvoting a user, and playing songs in the queue. To play songs in our queue, we use command line VLC to play the song in the background. To then check if it is time to play the next song or not, we check the system to see if the pi user has an instance of VLC running. If VLC is running we assume a song is playing, as VLC exits after a song has completed. If there is no VLC instance running, the next song is taken off of the song queue and played.

Inside the queue, we have a Song object, this object stores the song URL, submitting user, and the popularity of the user. Whenever we add a song to the queue, before adding the song, we update all the tastes of the Songs in the queue. This is because based on voting on the current song, multiple songs could be affected, so we need to refresh the popularity values from the database. After doing so, we then sort our queue, putting the most popular people's songs and the front, and least at the back where they belong. Then whenever a song is taken from the queue, we simply remove it from the front.

In order to instruct the AudioServer to upvote, downvote, or submit a song, the audio server reads from a linux FIFO. When told to do so, it will constantly read from a FIFO, taking commands that are sent through it. Two commands are "upvote" or "downvote", these intuitively upvote or downvote the current song, which the server keeps track of. The server then tells the database object to update the popularity of the user that submitted the current song. The final command follows the form "<username>;<URL>", this submits the given song URL to the queue under the username provided. The audio server does not do authentication for users, it is meant to be a backend module which assumes that users have already been authenticated somewhere else in the system. To allow the audioserver to both read from FIFO and play songs, it uses two threads to do so. One thread processes input from the FIFO while another thread checks if VLC is playing, and takes the first song off of the queue if it isn't.

With the AudioServer portion finished, the system needs a way for user's to interact with it other than sending commands via a FIFO. To do so we run a webserver using Webtoolkit or Wt. Wt is a webserver library written in C++ which allows us to host a webserver and build our website using widgets. This allowed us to write no HTML, PHP, or JavaScript(thank God), and instead use C++ to design our website. The layout for our website design is very simple, it is built purely for functionality, with 0 effort for A E S T H E T I C. Pictured below, it has text fields for a username and password and URL. There is then a register button that can be used to register a user. Another button allows a user to upvote or downvote a song, where another submits a link from a user. At the bottom of all these text fields and buttons, there is a response area. In this area text is written to indicate the outcome of any action the user attempts. Such as letting the user know they have entered an incorrect password or if they have successfully submitted a link.

The websever also have a reference to our sqlite3 database and send data over a Linux FIFO to a running AudioServer. The webserver primarily uses the database to authenticate users. Before any action can be performed by a user, they must submit a username and password. The webserver will then use the database the authenticate the user, if authenticated, the werbserver then sends the corresponding command over the FIFO to the AudioServer. When registering users, the database also ensures that a password is strong enough. We consider strong enough to be a password that passes the comprehensive8 or basic16 check as described by Kelley et. al. If the password is strong enough, we generate a 64 bit salt, compute the hash of the salt and password, and attempt to create a new row in the database with these values. Based on the return code of inserting the new user, we can tell if the username is already taken or not, and let the user know if it is.

To then start the whole system, which includes the audio and webserver, we have the audio server one in one thread, the webserver runs in it's own thread. They then share communication via the shared FIFO and the audio server plays audio out the 3.5mm jack on the Raspberry Pi. Below is a diagram of the final system that we implemented.


Testing

First stages of testing involved making sure that our abstraction for the database worked. This consisted of using the database interface we made to insert or query values from the database. In another shell we would then inspect the database directly to check to make sure we were getting the correct values.

Next we worked on getting the queue and having audio play. To do so we would prepopulate the queue with songs with varying popularities, then we would play the song at the top of the queue. We would then listen to make sure the correct song went off as we went through the queue.

To test the whole audio server setup, we would start up the audio server and then use the echo command to send various items down the FIFO. We would then listen for different songs to make sure they appeared in the correct order. In addition, we would look at the database to make sure that when we sent votes over the FIFO the respective users would have their popularity values changed.

To test the webserver, we would mostly test it by looking at the webpage and trying the buttons. Because different responses are outputted based on buttons presses and events, we tried different events to make sure the responses worked. We also would cat the FIFO that it had sends commands over to make sure that it sent only the proper commands. After this test we then combined the webserver and audioserver into one whole system and tested it by adding items via the web interface, but also by echoing commands to the hared FIFO.

Some issues we had along the way were knowing when it was possible to play the next song. At first we tried having one VLC instance, and adding songs to it's playlist. But we couldn't figure out how to reorder the playlist if popularity changed, or to add songs to the playlist. This lead to us having VLC exit after streaming a single song and polling the system to check is VLC is running before playing the next song. The other major issue we had was creating user sessions. We attempted to follow the Wt example that uses user sessions in it's web application. But due to the differing implementations in the downloaded examples and on the website due to major changes across major version updates they were hard to follow. We abandoned this effort early on as we did not want it to stand in the way of development and it was taking a lot of time in attempting to get it to work. That's why we leave user sessions to be future work, and instead had the user authenticate for any action they wished to perform.


Result

Overall the system ended up working as it was supposed to. We were able to play songs in order based on user's popularity rating by recieving URLs from both the web interface and over FIFO. While we weren't able to implement user sessions, we were still able to get a solid functionality. This lead to us jamming out to some great songs while testing in the lab.


Conclusion

Overall the Raspberry Pi was able to be turned into an effective web and audio server. The Pi was able to handle running the webserver for multiple users to submit links and vote. While also using VLC to stream music from youtube based on submitted URLs. Though some features could not be added as we had hoped, we got the baseline functionality accomplished.


Future Work

One major improvement we would work on if given more time is to have user sessions. Currently the user needs to input their username and password before they attempt any interaction. By having user sessions, optimally a user would only need to do this once. Another potential improvement would be to rate limit voting. Currently users can vote as fast as they can type their passwords in. While this may be desired or lead to interesting results, it may be more sensical to only allow users to vote once per song.


Work Distribution

Generic placeholder image

Project group picture

Generic placeholder image

James Cassell

jcc384@cornell.edu

Did everything.

Generic placeholder image

James Cassell

jcc384@cornell.edu

Did absolutely nothing


Parts List

Total: $35.00


References

Wt Library
VLC
SQLite
SHA256 Hash

Code Appendix

All code can be found in my audio-server GitHub repository at https://github.com/majorbonghits420/audio-server

Documentation for the code generated with Doxygen can be found here.