Dedicated Volumio Database and Play Queue?

I wanted to float some ideas by you guys to see what you think. Currently Volumio uses the MPD database and play queue system. This makes it tricky to integrate other track-based sources such as Spotify and Google Play. It is also sometimes awkward to switch between MPD, Airplay, and other modes.

If we implement a dedicated Volumio database and queue, we have more flexibility. Here are some of the possibilities (though I admit some are easier than others):

  • Database can present a unified filesystem to list tracks from all sources (like local files, NAS files, Spotify tracks, or Google tracks)
  • Database can store additional metadata like album art, star ratings, and tags in a way which is easily accessible to the Library system and the player GUI
  • Database can only update on demand, to limit the amount of traffic used refreshing information from remote sources. This allows it to be indexed and quickly searchable
  • Play queue can include files from different sources such as MPD, Spotify, Google, etc. It can skip, loop, and shuffle successfully between these files
  • Depending on the source of the track being played, Volumio player communicates with the appropriate playback daemon to read audio statistics, control seek, adjust volume, etc

If Volumio is not locked to MPD, it can also behave more like an audio-receiver and toggle between different modes:

  • Playing a queue of individual tracks
  • Playing a webradio stream
  • Receiving Airplay/UPnP stream
  • Receiving Pulseaudio synchronized stream
  • Who knows, maybe play live input from CD or phonograph :wink:

It looks nice and ambitious. After reading your post, I did a little googling and found this: mopidy.com/
I didn’t know it, but it seems to be quite interesting. Maybe a direction in the future would be to move out all MPD integration from the webui, and rely on this kind of multiple-sources music server.

I do agree perfectly that an unified queue will be the best solution. But since it’s long and ambitious (as jotak remarked) I think we should do it after the release. And since we’re planning to switch the whole backend to node.js we will rework with node in the process.

Regarding mopidy, that would ease our work a lot. I looked at it previously and I decided not to use it for one simple reason: sound quality. It doesn’t sound as good as mpd. And sound quality is the first priority of Volumio.
Plus, it’s not as flexible with playback options as mpd, (but of course can handle multiple sound sources out of the box…)

So, I think we’ll handle a unique queue with sql (or redis) and start developing it on node.js after the 1.5 release. What do you guys think?

Any idea about how we’ll plan this work? Ning-yu, did you start to work on it?
Someone (Meryn) suggests a very similar idea : volumio-core-system-t2036.html (btw, michelangelo, maybe he could have access to this forum since he’s also interested and wrote a pertinent post)

The picture he draws describes correctly the architecture we could implement.

Big picture: we would have:

  • Some “Source interfaces” (MPD and Spotify to start with, potentially more), primarily based on nodejs (but could have other dependencies). Each “source interface” communicates with its source.

  • A “Volumio sources controller” on the server side, based on nodejs. It talks to the source interfaces, knows at any time which source is currently active and should handle client requests. Communicates with client on websocket.

  • A “Volumio playlist” that mixes items from different sources. It should contain our own “random”, “repeat”, “single”, “consume” features (they’ll have to be reimplemented).

  • The client side is globally unchanged, except that must be adapted to websockets

  • For the time being, all the settings / other parts are still handled in PHP

  • Nice2have, that I would like to develop later: a “statistics” module, that is informed of each played song. I would use it for improving library search :slight_smile:

About the Volumio unified database feature you were writing about: we should list the pros and cons of such a unified database. I mean, having a cache system to limit the network traffic is a very good idea, but does it have to be unified across all sources? Maybe we wouldn’t want to store the same information from MPD, spotify and google?

Basically the question is: does this database/cache should be handled at the controller level (in which case is unified) or at the source interface level (in which case it’s not unified and can behave differently depending on source specifics features)

Yes, I think Meryn should join us to work on this! I definitely agree on the architecture both of you propose. I have not written any code yet (still learning node), but I’ve been thinking about how to implement it. Here is my thoughts, as far as I understand about the system:

If you PM me your email account connected to to Google Drive, I’ll send you an invite to share and edit!

For the architecture shown above, it would be nice to have all of the interface modules self-operating, thus making the system asynchronous and more responsive. It would probably require heavy use of the promises system in the node ‘q’ package.

For instance, when the Spop interface module starts running, it will automatically bring up the Spop daemon if its not already running, check the status of its library, run a library update if requested (or needed), run any self update routines, and then await requests from the core module. The Volumio core would interact with it using standard defined commands such as ‘ls’, ‘play’, etc. When a status change is detected, the interface module will push a notification to the core, which would then feed the update to clients.

Like you mention, it might end up being better to have each interface module handle its own library cache, and report the contents to the core module as a standardized json structure. This allows each interface to better handle the unique access requirements and data structure for each source. We would, however, need to agree on some standard data fields which would allow the core to understand the contents. Any extra data fields may also be included, in case in the future the core makes use of them.

Nice diagram

We’re on the same lines.

However there’s an upcoming issue we should think about: how to maintain the compatibility with other MPD clients, like MPDroid, which I think are heavily used among the Volumio community?

A best effort would be to “act” as a MPD server and give information on 6600 presented the same way MPD does, but including information from other sources. But I would probably not go for it, since it would be a lot of work and we’ve already much to do.

So another possibility is to load our own playlist in MPD only if its top element is a MPD song, and to show in that playlist only consecutive MPD songs. E.g: if my playlist is

  1. an MPD song
  2. an MPD song
  3. an MPD song
  4. a Spotify song
  5. an MPD song

Then we would load in MPD the playlist [1,2,3].

This way, if people use only MPD clients, they won’t notice any different (all their playlist would be full MPD)
If people use only webui, they will be given this improvement of multi-sources playlist and everything’s will be fine
Only people who use both webui with mixed playlist and an MPD client would see some limitation in the MPD client

Yes, that makes sense. Looks like doing it this way also preserves gapless playback. And when playback hits a block of Spotify songs, those songs will be queued up in Spop and played, so that block is also gapless (if Spop supports that).

If shuffle playback is selected, there are a couple of options for handling that. You can just queue up individual tracks in the daemons when the tracks are selected, or you can explicitly shuffle the entries in the playlist, which will allow for contiguous blocks to be identified (although you would not really need gapless playback in this case).

A suggestion about the language: would you guys be comfortable with writing the code in Typescript ? ( typescriptlang.org/ ) Some words about typescript:

  • It’s a superset of javascript. It means that some Javascript code IS ALSO typescript code. If you can write javascript, you’re very very close to write typescript.

  • It compiles to javascript. We write typescript, generate javascript from it and then we can start node with the generated JS

  • It allows to specify variable types => thus, reducing risk of bugs, having better-structured code
    Eg. function setUseCacheFile(useCacheFile: boolean) { // ... }

  • It allows to create classes and interfaces, the same way you would do in common object-oriented languages.
    Eg., for SourceInterfaces we plan to implement interface SourceInterface { enabled: boolean; play: (path: string)=>void; // meaning that all source interfaces have to implement a "play(path: string)" function stop: ()=>void; // meaning that all source interfaces have to implement a "stop()" function // etc. }

  • So because of this mainly, it’s better for writing medium/large scale projects

  • Typescript shows us what javascript will be in some years: it’s EcmaScript-6 compliant, which means that future javascript versions will more or less look the same when EcmaScript6 will be released. For your information, the very popular google’s Angular 2.0 will also be built on top of Typescript. So if you want to look forward, try typescript :wink:

What do you think? Are you ok with that or not?

Yes, Typescript is probably the right way to go. I had tried to set up typescript syntax highlighting in my vim environment, but got frustrated it didn’t work. I proceeded to just edit the compiled js files instead. Maybe it’s time I gave it another shot. :confused:

Personally I use bracket for coding: brackets.io/ I find it very pleasant to use
With a NFS share mounted on my desktop, it’s just perfect :slight_smile: It has some typescript extension for syntaxing colouring, error checking and even some autocompletion

My bad I completely missed the last posts. Really really really interesting discussion.
Preliminary thoughts:
I already think that a modular approach is the best, with distinct databases that are sent to main one via a common standard. To preserve mpd clients we can act like you suggested, and send mpd commands as our core was a client (something that volumio does yet).
So yes, I like the idea of “Volumio sources controller”!
As for typescript I’ll give it a look!
And I agree on joining merin.
Guys, really happy. Things are coming together. We’re gonna have fun!

I’ll give a look at typescript too. That seems very interesting and usefull for our purpose.

Edit: off course I agree with your architecture proposal.


Thinking on what jotak said:
“A best effort would be to “act” as a MPD server and give information on 6600 presented the same way MPD does, but including information from other sources. But I would probably not go for it, since it would be a lot of work and we’ve already much to do.”

This is the way to go in my opinion. It is actually quite a big work to do. But this will allow us all the flexibility we need. And in the end we’ll be able to manage all the services in a simpler way, wrapping every request and every response in appropriate way.
Plus, we would have implemented this mechanism on evey single service anyway, so in the end the additional work is just miming mpd protocols and hooking to our methods.

Here are some additional thoughts about play queue and db, and volumio core engine:

  • To mantain compatibility with third party clients and ensure we have full control and flexibility over play queue my opinion is that exposing our core as mpd is the key.
    This way we are basically acting as mpd, on port 6600, and receiving commands (and sending status) from there.
    The idea is to use a single playlist, listing every item (mpd, spotify, gmusic etc). It will be exposed as regular mpd playlist. Once played, every item will be played by the correspondent service. This playback mechanism will be handled by volumio core, and the status will be sent to clients\web ui as it was mpd.
    So we are miming what mpd does, but implementing the playback mechanism we want for every service.

So this is what goes on:

WebUI and Clients connect to Volumio core on 6600, with same MPD protocol
We have our play queue exposed as normal mpd queue, even if there are non-mpd items.
We define the parameters for each item type. Like: service, daemon, port, communication protocol etc.
When we receive a play command from client\webui, we just play the item according to the above rules.
We notify status via mpd protocol to client\webui

Scenario:

Playlist
1- mpd item
2- spop item
3- gmusic item
4- mpd item

From Client\WebUI

  • I see the complete playlist. I enqueue it and play

On Volumio Core

  • I receive the add & play command
  • I look into my db and set each item type, and which playback mechanism I should use:
    Play track one, send mpd play for mpd item, mpd plays it.
    When mpd finishes playing it, I know I should use spop now.
    Play second track with spop, sending appropriate spop commands
    When spop track finishes
    I send play with gmusic parameters and so on

Other scenario (search)

On Client\WebUI, the user searchs for “Bowie”
Volumio core receives “search bowie” on 6600 like it was mpd
For every active service, volumio core queries every service and reports results to volumio core
Volumio core then wraps results and sends them in mpd response format to client on 6600 (eventually adding tags to tell if is a mp3, spotify or google music, for example adding a [SPOTIFY] to tile)
WebUI\Client selects a spotify reply and plays it, sending addid (id of results) to 6600
Volumio core interpretes the id and sends to spop the appropriate play command

So what we need to do:
1- Recreate and mime mpd behavior on listen\send status
2- Implement the controlling pattern for every service. Ideally we should define the same type of methods and patterns for every service type.
3- Define our db structure to know which item type we have, and all additional information (rating system…)

ADDITIONAL CLIENTS support
To ensure future compatibility with other clients (spotify connect, windows media etc) a good idea would be designing the mpd control wrapper as a separate layer. This way we’ll have a Volumio Core API which could be used to hook just mpd initially, and then extended in a simple way with other protocols. There is not much additional work in the Volumio core, but it would be definetely a good idea.
As an implementation note, we shold think in a more abstract way, not tie our methods exclusively to mpd one’s.
Otherwise for each new service wrapper integration we can occur in alose lose situation

  • change the volumio core API (and alle the existetn wrapper)

  • add a the new service without some specific features

E.g. consider the mpd play call wich take just the ID parameter. Thevolumio core api should expose a play method wich takes for example a
map of key – value, in such way the wrapper will be able to parse tompd play call, put the ID parameter into the map and call the Volumio
Core play method.

The volumio core play method read the request and call the appropriateservice (spoop, mpd or another) with all the required parameters
needed by the service API, In this way the same volumio core API wiilbe able to run (through) the specific implementation any service play
call.

Conclusion and potential issues:

  • The initial phase will be quite a big task, lot of work involved. But when this will be completed, the rest of development should be pretty fast.
  • The system will be modular, thus quite complex. We should assess if this will compromise system performances
  • This will be a great step forward. There could be good chances that Volumio will be THE audio player
  • We are a great team of 5 people now. I’m sure all the right ingredients are there

What do you guys think?
VolumioArchitecture2.gif

Hi guys!

Havent done an introduction, so I think its appropriate to start with this. I’m Merijn from the Netherlands, a Computer Science student. My interests lay primarily in embedded system/domotics, which is probably how I found Volumio. I do have lots of programming experiences, just not in any of the languages Ive seen in the Volumio git, but I am wiling to learn new stuff. After using Volumio for a while I decided to build a dedicated Android app which mimics the web-UI, and completely Volumio-themed. After having the MPD-control done I was thinking about integrating Airplay/Spotify, which brought me to the suggestion I posted.

As I told Michelangelo in my message last night, theres some ideas I would like to share with you guys. Now that Im done reading this discussion, there is not much left to share to be honest. :slight_smile: Pretty much everything I had in mind had been discussed and Michelangelo summed it up quite nice in his last post.

I too, think that it would be best to have the core ‘act’ as a MPD server, to keep it compatible with all the applications current users are using. Even tho this is probably not the highest priority right now, there are some things we have to keep in mind.
Let’s say someone enters a search request in his favorite MPD client. Normally the MPD would return its results based on the servers database. If we are going to include Spotify/GMusic/UPnP/etc search results in the same response, and one searches for short keywords, this will result in a huge response (mainly because of Spotify).

What about using Shairport/UPnP? Most MPDclients (note: I’m an Android user, so it might be different for Apple/Windows users) do not have an option built-in to stream local files. Does this mean Volumio will need a dedicated app? I know Digx is delivering great work with his Sound@Home app, but does not support airplay yet (altho it is on the todo list). I could be wrong here, but as far as I know, we will have to use 2 apps if we want to mix streaming with nas/spotify/local files.

I do agree on all interfaces following the same protocol. This keeps the system flexible, and will make it easier to add new services. Your diagrams look awesome as well! May I ask what program you use to make these Ning-yu?

I am REALLY stoked about this, I truly think Volumio has the potential to become one of the biggest players! At least one of the most extensive ones. Once this new system is up and running, we will be able to make big steps.

I do no have much experience in contributing in large projects like this one, so please let me know whenever I’m running too far ahead or thinking into the wrong direction. Thanks.

Meryn

Hey Meryn, welcome! :smiley:

I feel that the MPD socket protocol is a bit awkward since its output is difficult to parse. For example, a typical status message may look like:

volume: 49 repeat: 0 random: 0 single: 0 consume: 0 playlist: 168 // <-- this often increments on its own for no apparent reason playlistlength: 4 mixrampdb: 0.000000 // <-- some unused fields state: play song: 1 songid: 2 time: 42:0 elapsed: 41.990 bitrate: 128 audio: 44100:24:2 // <-- colons should be reserved for separating key:value only nextsong: 2 nextsongid: 3 OK // <-- sometimes this is replaced by AWK if there is an error
For the Volumio webclient (and other non-MPD clients), I feel it would be easier to do a JSON-based protocol similar to Spop. At the same time, however, I also agree with you and Michelangelo that it would be a great to have MPD emulation in order to interface with third party MPD clients. Maybe the best way to do this, as shown in Michelangelo’s picture, is an abstraction layer that sits between the core and an external MPD client. This layer speaks JSON with the core, and speaks MPD with the external client.

It’s just a Google Drive Drawing. :wink: I’ll be happy to send you (or Michelangelo and Hooch) a share invite, if you want to edit or clone it. It’s a public sketchpad.

I think that the JSON standard for comunication between Volumio Core and the various abstraction layer will be fine. Off course every abstraction layer need to send the response in a proper format, by the way we can define the standard volumio core API too. In this way the WebUI will talk dorectly to the core and any volumio custom client could be implemented according to the specifications above.

@Hooch, I like that idea. JSON is really ideal to use with the GUI.

I’m not sure abotut the backend integration. As a database; maybe a good option would be is Elastic Search. I have no idea how heavy the initial load is, but the db is quite powerful and would be able to provide much more than just storage. Most important of all, it’s very fast :slight_smile:

But I guess for any use case, any DB would be very fast. I would strongly lean towards a NoSQL solution myself, but then again, I’m less of a DB guy.

Hi,
I also agree with the abstraction layers, and Volumio having its own json-talking layer as the default one.
About DB: I talked with a mongo “evangelist” some weeks ago, because I also thought some NoSQL DB would be more interesting than SQLite. He advised me not to do it, because SQLite is as far as I know the only kind of DB that doesn’t take any resident memory for daemon. So it’s best fitted for small platforms such as pi, especially when there’s no very frequent DB requests , which is the case with volumio. Mongo uses a daemon. So does elastic search, which is suited for big data, it’s not our scheme. So except if some of you guys know some nosql version of a sqlite-like executable, I think the best is to stuck on that.