Yio Remote Community

Added ROON integration and media browsing

@ChristianRiedl I’ll start with the 2 unrelated questions:

  • I am cross compiling for the pi in a Linux VM and then run the app on the pi from Qt Creator. This way I can see the console output on my computer, but test the speed and everything else on the actual hardware itself.
  • It is possible to load QML files from the filesystem. Only difference is that you need to give a path to the file and start with “file:” instead of “qrc:”, which refers to the QML Resource file. I might add that loading from a resource file will be always faster, because then you can use qtquickcompiler, which translates the QML files to binary. As far as I know.

I wouldn’t hide the search in a contextual menu. Rather do it the way, I proposed in the UI above. We can still filter the search for various services, basically just adding more “tags” to the list, where I have “All”, “Artist”, etc. This makes the user experience a bit better I believe.

We can still have a “Search this” in the contextual menu, that initiates a search based on the item.

@ChristianRiedl Hi Christian, I’m working on the remote-os build and developer image. So far I haven’t debugged on the RPi yet, only on the local machine as Marton described it. The upcoming documentation will cover the setup of Qt Creator and the crosscompile toolchain for Linux. For the remote console the following magic run environment variable in Qt Creator is required: QT_ASSUME_STDERR_HAS_CONSOLE=1
For remote debugging gdbserver is required on the RPi. I can look into it and add it to the developer image if you require it. Sooner or later I’ll probably need it as well. At the moment I have a bunch of other things to finish which don’t require a debugger yet :slight_smile:

@Nklerk
You are talking about a self implemented search delivering a whole resulting hierarchy of object to the UI. For me search is an operation which is nearly the same than browsing a static hierarchy the only difference is that for a searchable item in the hierarchy I only have to apply a search string and ROON delivers a hierarchy with the same kind of items (albums, artists, tracks) as the static hierarchy. You can browse into this dynamically created hierarchy in the same way as into the static hierarchy. This is how ROON works.

YIO hardware is poor I am happy that ROON at one time delivers the hierarchy piece by piece, controlled by the browse operation. The UI gets at any time only one item and their children.

If I would have to implement the search by myself, I would do it in a similar way, building a dynamic tree with artists, albums, tracks and delivering it to the UI in the same way as the static items.

I am only thinking about music, I guess you also think about movies, maybe photos too. This is not my intention. When I want to watch a movie I already have a big screen, where I can see and select my movies from the DLNA server. I cannot imagine to replace the small and intelligent SAMSUNG TV remote by YIO. It is not IR, it communicates with SAMSUNG SmartThings protocol. There is place on the table for 2 remotes.

@marton
@Nklerk

Some more ideas about hierarchy and browsing. My top hierachy looks like this

TOP
    Library
        Search (local)      searchable !!!
                  Artists   dynamic !!!
                  Albums    dynamic !!!
        Artists
        Albums
        Tracks
    Playlists
    Genres
         Genrexy
              Albums
              Artists
    Internet Radio
    TIDAL
       New
       Search TIDAL    searchable !!!
             Artists   dynamic !!!
             Albums    dynamic !!!
       Favorites

My current “generic” browser simply drills down from the TOP, detects a searchable item, makes the search and drills down the dynamic hierarchy. I accept that “generic” is sometimes not comfortable and propose to define additional **entry points ** like

  • Genres
  • Internet Radio
  • Playlists
  • Artists
  • Albums
  • Local search
  • TIDAL Search

So when the user selects one of this entry points I will jump immediately to the point in the hierarchy. The keys which are delivered by ROON are generated and unfortunately not fix, they change whenever you drill down. So for the entry points we have to store the path (we are back at the path Niels).

So the entry points is a list, each item containig

  • display name “Search TIDAL”, “Search Local”
  • the path “/TIDAL/TIDAL” search or “/Genres/genrexy/Albums”
  • is searchable

I propose that the integration delivers a list of possible entry points. The user should be able to disable and change the sequence and display name. Maybe in the web_configurator, or on the YIO.

I also can imagine that there are user defined entry points. When the user browses down he can add something like an entry point to “Favorites”.

In this case it is required that in the browse results item list we add a path property.

Lets do a couple of steps back. We are chatting sideways I believe.

I know you are ahead with your integration and we are very happy with that. The thing is that we want to make the browser a generic UI element as it will be used by other integrations with different hierarchies. we also see more use cases for the browser UI element other than the obvious media library.

Our goal is to design the browser both UI wise and Technically from the ground up to be used by every integration that’s coming. and obviously you will be the first :slight_smile:. We want to do this as quick as possible so we’re not holding you back to much.

The git issue describes essentially two functions right now. These functions need to be present on the integration and are called by the browser UI for content. One is to get a listing of items and “Folders” to browse and the other is to interact with a item, I.e. play an item.

The Json contains example data how this could look like. including folders pointing to a deeper path. and items. When the user taps a folder then the UI will again fetch the browsing function so the integration can show the data of a layer deeper.

I believe the structure you described is very possible with this proposal. my question is, is there anything you are missing in that format proposed?

I hope I understand now. You want to create a hierarchical dictionary containing all integrations. And all integrations should implement an identical set of functions like getItem.

The top level for one integration is more or less statically, but deeper the integration typically fetches it asynchrousely, so the result must be delivered using signal. If you require that it is a fast, synchronous operation this is very expensive thing. The integration must store somewhere the whole hierarchy and synchronize from time to time. And this hierarchy is quite big because the same album occurs on different places in the media hierarchy. For ROON there is the special situation that I must use item keys which are generated by ROON and which are changing, they are only valid as long as you don’t browse to another place.

I am not sure if we really need a path to navigate in a directory. Browsing is also possible with goTop(), goBack(), goChild(item key) and some unique item key. A path is required when you want to store the path and reuse it. For this case it would be sufficient for have a getPath(key) and a goPath(path) function. All the goXxx functions are asynchrous.

So for me the key question is if you expect the getItem function to be synchronous.

One thing I would like to add is the set of operations available on an item (a string list). the supported_features in the entity configuration is not sufficient for a hierarchy of a different kind of items.

I don’t think that @Nklerk expects it to be synchronous. We are moving all parts of the code to be async, using signals and slots. But correct me @Nklerk if I’m wrong.

The UI will not be aware of the structure. Just rendering what is provided by the integration. With your structure as an example. When the browser is activated it will fetch the root by calling the function in the integration. The integration respods with the data to represent the root. I.e library, playlist etcetra. These items contain a path value provided by the integration that is used when going deeper into the structure. So for library the browser would call the function of the integration and passes the path of the selected item. I.e for library this could be /library/ (or whatever the dev thinks works best for that integration)

The integration will then return artists, Albums, tracks etcetra. So everything that’s being displayed will be provided by the integration. And thus is every thinkable structure possible. Also for the dev its quite simple as only the specific path have to be fetched. When using url based images these will be rendered async by qt. I can imagine that this isn’t always possible to fetch images based on a url or when a dev needs specific images then base64 can be an option thus included in the example.

The json formatted response won’t be asynchronous because that won’t be possible to parse. The integration should never interact with the UI directly. If there’s another way im missing then please let me know

@marton

Voilà, ROON integration works with your list models and QML views. But:

ROON has some very bad characteristics :

  • The worst is that the item ids you get from browsing are only temporary valid. You can use them to browse down or to play the item. When you browse some other things before you use this items they are not valid any more. To make it work as planned by your design requires to keep somewhere the item keys and titles and to browse again for the item using the title. This is quite complicated and requires some time. So I hope that we can integrate the “generic” topdown hierarchic browsing too.

  • For searching there is also the problem that the item ids got for an album cannot be used to browse into the album to get the tracks. I have to search the album in the album list and then I can get the tracks. But this is already solved.

I know for most of “streaming” users searching has highest priority. But for people like me a hierarchy Genre – Artist – Album has the advantage that the number of results you get at each level is typically not too large, so you can select it by scrolling.

Before I start to make changes I want to discuss the changes I need.

  1. Simple, to build the search model it would be helpful make the items of the SearchModel accessible from outside. ’
    QList<SearchModelItem*>& items() { return m_data; }

  2. We must find a solution for the play commands without requirement to add new functions to the mediaplayer entity and ContextMenu.qml
    I propose to add the command as third parameter to the playMedia function. And to define a fix set of possible play commands.
    I would like to have PLAY NOW, PLAY FROM, PLAY NEXT, SHUFFLE, QUEUE, RADIO to support all ROON possibilities.

Developer questions:

What is the intention of the count property in the SearchModelList ?
Your SearchModelList append/insert function calls for every operation the begin/endInsertRows. I think it is good when the rows are added asynchronousely. I can imagine that it is more efficient on poor Pi Zero when we call this functions only once when inserting synchronousely 20 items.

In general the result of a search can be quite big especially when I search on TIDAL (I think Spotify is the same) for Pink Floyd, I get several hundred tracks. I think too much for the Pi Zero. Did you try it ? Implementing some paging is also quite a lot of work.

That’s awesome @ChristianRiedl!

Seems like ROON is special in this case. I’m sure we can figure out a system that could work. I am thinking that all these things could be handled in the integration. Keeping track of ids, etc.

We could add that access of the model.
That could be a good solution to send the command as a parameter. However for the commands, let’s make a list of what you would need, what Spotify has, etc. So we have a pool of commands that probably could work for most situations. Maybe @Nklerk can also pitch in with ideas.

I have looked at loading just let’s say 20 items and then loading more when you pull down at the end of the list. QAbstractListModel supports canFetchMore() and FetchMore() that we could implement.

I haven’t tried loading too many items into the list. But I know that ListView only renders the visible elements, so UI performance-wise it doesn’t matter.

@marton

So we will have a solution with a fix set of play commands with one playMedia function.
I vote for PLAY NOW, PLAY FROM, PLAY NEXT, SHUFFLE, QUEUE, RADIO.

What are your further plans with media player ? Do you plan to add hierarchical browsing ?
For streaming guys your current search solution is the right way. Maybe recentSearches should be stored in a file to survive a restart. I could implement a universal persistence feature to store/load some objects.

If you have no time I can start a prototype for hierarchical browsing based on your current models and qml .

Are there other jobs for me ?

Web Configurator is on the right way with Vue.js and TypeScript, But I don’t agree with the technology mix, I will not participate.

For other smart home integrations I have no test possibilities. There is some interest on DLNA/uPnP but for playing music DLNA functionality is not sufficient, and expensive to implement.

For my personal use I think about combining TV IR remote with a TV program. But there is no “standard source” for TV programs. And as every TV has some kind of TV program (EPG) there is no big advantage to have it on YIO remote.

In the past we also talked about a “free form” display for individual display of readonly information. But this is for 90 % a UI job.

There is one thing I am interested to implement : Recipes. A feature to combine entities of different integrations, support delays, some logic. But it requires to make some specs what is needed. I think Niels is a compentent man to figure out what is required.

@ChristianRiedl

What does PLAY FROM, PLAY NEXT do? Isn’t PLAY NEXT is similar to QUEUE? I think these are sufficient for Spotify and co streaming services as well.

Yes, that kind of browsing is on the todo list. I am working on some UI changes that will make it possible. I will push the code to github in the coming days.

The TV Remote in general is the next thing that is on our todo list. Combined with the dock’s IR capabilities. I’ll open a topic for it.

@marton

ROON Play Commands

  • PLAY (on ROON named PLAY NOW), interrupts current playing and immediately starts the new TRACK, the queue is cleared
  • PLAY FROM is like PLAY but adds also the remaining tracks from this position to the queue
  • PLAY NEXT inserts the new Track after the current playing track
  • QUEUE inserts the new Track at the end

TV Remote : IR + configurable UI, depending on features ?

@ChristianRiedl I get it. These commands will work also with streaming services I believe. Let’s use these, we can always add more. @Nklerk do you have ideas?

I’ve created a topic for the TV Remote/IR.

I believe we should not limit but standarize as much as possible. Hard task but doable

This integration was the sole reason for backing the YIO Kickstarter. I’m looking forward to getting my hands on it.

1 Like

Hi @ChristianRiedl first of all I want to thank you for integrating ROON. ROON is 1 of 2 reasons I backed the project and I was wondering if there is any footage of the integration in action?