-
Notifications
You must be signed in to change notification settings - Fork 237
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle Airplay stereo group as one speaker instead of two individual speakers #1413
Comments
Thanks for opening this issue. I'm thinking if we should expand the scope to include grouped speakers that are not in stereo mode? When changing this stuff it would be nice to do it in a way that can support this too. Could you also share screenshots of iOS speaker selection, both with a stereo group and a non-stereo group? In the former case I understand the individual speakers are not listed, but it's not clear to me if the latter case shows individual speakers? And if so, how (is there individual volume control?). I'm also curious how the Remote app shows grouped speakers - if it can, then we have to check how grouping is communicated via dacp. With regard to implementation, my initial thought is that |
From what I have seen so far, this is basically the same. Internally, then stream must be sent to any of the peers in a group, no matter if it is a stereo pair or any other group. The main difference I have seen so far between a custom built group and a stereo pair is the ability to assign a name to the stereo pair ("gpn" attribute).
Will attach screenshots for as many scenarios as possible.
I had the same thought. I was actually moving back and forth between the two. The true challenge that I see Is that we have two or more group members and on the UI side, we only want to show one speaker. So enabling the speaker and thus the associated (single) output_device is not sufficient. We will need to translate between the UI portion and the backend logic. My idea was also to move the info into the Once the speaker is selected, the UI would know that the speaker is a group and trigger playback on any output_device with the same group_id. |
Screenshots: Below you can see how individual speakers can be selected in the Airplay control panel. Once the connection is established, a checkmark is shown: If the Airplay control panel was closed and is opened again, the selected speakers will be displayed as a group: The group entry can be unfold by tapping on it, showing the first screen again. The even two groups can be grouped together into one (basically this dissolves the other group, no nesting occurs): The entry changes its icon depending on the content of the group. This time including an Apple TV: Unfolding the entry shows all members individually (like above with two speakers) and now folding is possible except for closing the Airplay control panel and reopening it: Legend: The above example is using the following devices:
|
I have spent some more time analyzing the metadata for the scenario below: We have a Sonos/Symfonisk speaker, a stereo pair of (legacy) HomePods, and a single HomePod Mini. The speakers are the following:
Below is the mDNS dump for this setup:
Observations:
|
Not sure I quite understand this. Like how are the speakers negotiating group id? The mdns output is also very different from what you shared here. Even the length of the group id seems to have changed? In the previous post the stereo Homepods Links and Rechts even had different gid's, which is confusing. |
Hmm. The different gid values for Links and Rechts are weird. Maybe I took the snapshot during a reconfiguration of the setup? Regarding the negotiation. This is nothing that happens magically. The user initiates the setup of the groups and thus its either the device in the users hands that does all the configuration including the creation if identifiers, or the first speaker in a group takes the lead. However, it does not matter for our scenario because owntone is just taking the resulting metadata. I would not try to build groups from the owntone UI. I guess the rule is:
Makes sense? |
Good catch. However, the gid still is the same if you strip off the data after the first '+' character. I would suggest to apply the above rules but to strip the gid down the first of the three entries. Maybe one day we can figure out what the rest of the data means.
I found similar data for the other stereo pair:
The data after the first entry of the gid cannot be found anywhere else in the mDNS dump. So no clue what this could be. The second entry is zero for both entries probably is does not indicate left/right. |
Could it mean that a speaker can be member of multiple groups? Where each group is separated by '+'? I suppose we should then take that into consideration when implementing it in owntone. Maybe struct output_device needs to have an array of groups. |
I don't think that this is the case. First of all, I did not find any reference of the third parameter anywhere. To me, the grouping is mainly a UI thing. The only case where I see speakers being in two groups is stereo pairs where the initial group is the stereo pair and the pgid forms the group. I would say I have a fairly broad set of devices here in my house and I have not been able to build other groups like the ones we have seen. The key difference between groups is that the ones we can build manually in the Airplay control panel have a transient character. And I must admit, I do not know when they get dissolved. The stereo pairs are persistent (and cannot be built from the Airplay panel) and have a name. Same is true for Sonos stereo pairs. These even completely eliminate the two speakers from Airplay and replace them with a single speaker. The stereo playback is basically handled by the Sonos logic itself. |
Just wanted to update that I intend to contribute to this however I am not able to get my stereo pair working correctly. I have realised that my stereo pair is not actually forming despite the Home app showing the group has been created. @ma-ku - are you having any issues with your HomePods? I have tried everything including resetting both HomePods and I am still having no luck. In retrospect I realise I've had this bug since I deployed 15.4. Initially I thought this was a transient issue where the HomePods were configuring themselves but actually my stereo pair has never formed correctly. UPDATE - it has sprung to life. |
Since we do not know the protocol required to setup speaker groups, we will just digest what is provided by mDNS. I was thinking about expanding the output_device struct with the two group ids (pgid, gid) and the group name (gpn) if available. On the UI side, the behavior of I am not sure if it suffices to only provide the information about the groups and nesting on the UI side. There it would be possible to introduce a new speaker type that represents a group (and has children). The resulting JSON would be comprised of speakers and groups whereas a group can only contain speakers (max height two for the tree). This would keep the UI simple. The group would get the name built from the names of the speakers. Stereo pairs would again be treated as a speaker but could reference the underlying devices represented by Selection of speakers would then internally be dispatched to the associated players and vice versa. @ejurgensen: Does that make sense or do you see any issues with that approach with regards to other areas of the code? |
Yep. Things need some time. As I already alluded to in the other issue. Sometimes I was too fast and this messed up the observations. Good to hear that you are back in the game. Stereo is working? |
Yes - it is. Just tested with stereo! It took several hours but it got there in the end - I've never seen that before 15.4. No doubt there are a few bugs Apple need to iron out. |
I've done some testing of the way the Remote app works with the Music app on MacOS 12.2. Here is a screenshot. I have noticed that this is actually a little buggy. For example, the Apple TV output only shows if the output window is selected in the Music app as you see in the second screen shot otherwise it disappears from the list. For reference, my two HomePods are configured in a stereo pair and set as the default output for my Apple TV. You can see they show as an Apple TV in the Remote app and the app has no awareness of the underlying speaker configuration. I have checked and it is working correctly as you would expect. Should this be the MVP for OwnTone functionality? |
I'm not sure I completely understood the idea, so pardon me if I got it wrong. I'm thinking that we have to take into account that the player (via speaker_enumerate) serves speaker lists to multiple interfaces, and that some of them don't have the concept of groups. So while the json API/web UI can be modified to understand groups, there are limitations with regard to mpd and also dacp, as it would seem from @aleszczynskig screenshots. So it would be easiest if speaker_enumerate is modified, so that it doesn't necessarily return individual speakers, but rather groups plus non-grouped speakers. That would be in line with the MVP you suggest @aleszczynskig, and should mean that Remote (and mpd) without any further changes displays a list similar to the above. The suggestion you have @ma-ku about using a group type sounds sensible to me, since in the future a group could perhaps even contain a mix of Airplay and other devices. Then later we could add expansion of groups, individual volume control and maybe even creating groups. This would require that either in player.c or in outputs.c there has to be group <> individual speaker translation. The most appropriate place is outputs.c, but I'm not sure if that is possible. |
@ejurgensen´: Thank you for your insights. I will take a first step and implement the mDNS parsing and the JSON generation. And then we can see how things come together. |
Never mind. Airplay 1 vs. Airplay 2 selection killed my precious data. |
Update: The general handling of the mDNS data is in place. However, the mapping between device and speaker_info is problematic as the device.id is used also as speaker.id. Since we now can have a 1:1..n mapping, this is getting problematic. Any advice before I start digging deeper? |
I have pushed a first version that shows stereo speakers as one device and forwards start/stop events to the underlying individual devices. With that the first step is taken to support groups. I did not have the chance to test various scenarios such as authentication and other use cases. |
@ma-ku - thanks for your efforts on this? Where have you pushed this too? Is it a branch or your forked-repo? |
In a branch feature/grouping on my fork. |
@ma-ku Is there anything special you need to do in yours to get the group to show instead of the individual speakers? I tried to run your fork and it doesn't seem to show the group but I may have done it wrong. |
Well, check that you have built from the branch. And also be aware that this (intermediate) version only shows stereo pairs as ones Groups are the next iteration. At first I had to handle these devices that are statically grouped. Next step would be handling of speaker groups. |
I did build from the feature/grouping branch. git clone https://github.com/ma-ku/owntone-server.git /tmp/source/owntone && I have 4 stereo pairs and they all show up as individual speakers and when I hover over show they are only using AirPlay2. I tried to modify the linuxserver DockerFile to build yours. Maybe I did something wrong there but I don't see it yet. https://github.com/shauder/docker-daapd/blob/master/Dockerfile |
It looks like you haven't pushed the changes @ma-ku? The diff doesn't seem to have the changes you describe: |
Forgive me. You are right. Somehow the initial push never made it and I did not verify. Code is up on GitHub now. |
Never mind. Changed user in owntone.conf also to root. Not the best way but OK for development for now.
|
I rebuilt the docker image with the new commits you pushed and am having some success. I noticed when it first starts the speakers are still on their own. After a while I came back and most of them seem grouped. Right now I only have one pair as 15.4 and when i select their group I get audio from both speakers. Will upgrade my other homepods and do more testing. Here is the image for anyone else that may want to test.
|
My setup right now is: Living Room: 2 Stereo Homepods and AppleTV with HomePods as default audio Everything is 15.4 developer beta. When OwnTone first starts everything shows up as an AirPlay1 device. Both all the HomePods and the AppleTVs. Then eventually the Bedroom pair/tv shows up as an AirPlay2 grouped device that I can select. Sometimes the Living Room pair/tv also show up and I have successfully selected both pairs as two objects in the UI and had audio coming from all 4 HomePods. The office pair has shown up as an AirPlay2 pair but every time I have tried to select it, it disappears and doesn't play. I am not seeing anything useful in the logs to share. I may need to enable a debug setting but I am not sure. If there's anything I can provide to help let me know and I'd be happy to test and share. The first Living Room entry is the AppleTV and same with the first Bedroom entry. The Office entries are each of the Office HomePod stereo pairs showing up individually. The second Living Room and Bedroom entries are the grouped Stereo pairs that are also default audio on the AppleTV's. I tried resetting the Office HomePods and regrouping them but it does not seem to have fixed anything. |
@shauder In general, the devices can be detected as Airplay 1 devices and as Airplay 2 devices, typically as both. In earlier versions the Airplay 1 version took precedence over Airplay 2. I changed to logic in that way that a device that has either a device grouping (stereo pair) or a playback grouping (ad-hoc grouping done via the Airplay control panel of iTunes), then this device (Airplay 2) takes precedence over the Airplay 1 device. Now the challenge; I was working on the latter type of grouping today and was already able to render groups in the UI but every time I changed the config in the Airplay panel, the mDNS information somehow got messed up. It sometimes takes a while until these changes have been properly sorted out in the metadata. It even felt that these updates were not properly propagated from the underlying mDNS client implementation to owntone and so the internal metadata was left garbled. I will need to further understand why things start getting messy at some point. What is helpful for the analysis is a dump of the mDNS data in your network using You can look for the metadata yourself:
gid sometimes has a '+' separator, only the first entry denotes the group, the other values are unclear at least for now. So if you run into an incorrect scenario, then grab the mDNS dump and post it here. We can sort it out. |
@ma-ku thanks for all the work you've done already to get this started it's really awesome to see! I am posting this all only to provide more info in case it helps.
This generally describes what I am seeing. When OwnTone first launches all of the devices show up as non-grouped AirPlay1 devices. If I let everything settle down for a while then the AirPlay2 stereo pairs show up within the UI. Here is after I left it settle for a few minutes: The top two entries here are AirPlay1 entries for the Living Room Apple TV and the Bedroom Apple TV. The next 3 entries are AirPlay2 entries for each of my 3 stereo HomePod pairs I have connected. The two stereo pairs that are selected as default audio output for the Bedroom and Living Room Apple TV's show up as the Apple TV name instead of the stereo pair name (Their actual names are 'Bedroom HomePods' and 'Living Room HomePods'). I also find that I am only able to select and play music to the stereo pairs that have Apple TV's. The Office, which does not, will deselect when I try and select it and switch from being two AirPlay1 devices to AirPlay2 devices. This is my setup and also my avahi-browse output.
|
Hi all, i have just pushed a new version of the code to my repo. It contains initial support for playback groups in the sense that playback groups get detected and displayed as an entry with the name of the speakers concatenated with a plus character. However, selecting these devices for playback is not yet possible as the internal mapping between speaker and devices needs to be implemented. This new capability is already embedded in the backend but the UI portion of it must be activated by defining the symbol SPEAKER_GROUPING when compiling the code. @shauder: I also came across a potential solution for your problem. For reasons not yet clear to me, sometimes the Airplay 2 entries of a device gets overridden by its Airplay 1 representation and as a consequence, the additional information for grouping and stereo pairing is getting lost. You can prioritize Airplay 2 over Airplay 1 by defining the symbol PREFER_AIRPLAY2 when building the code. |
Different topic: UI improvement: @ejurgensen: I am thinking about also providing the corresponding icons in the UI similar to the Airplay panel in iOS. I cam across |
It's a good idea to support more exact icons. In theory, outputs.c/h should only work as a general abstraction, so it goes against the design if device type lists for all output types need to be maintained there. Could the objective be achieved by making a function that lets the player request output details? Or if there is some other generic way the output abstraction could collect the device types from the output modules. |
@ma-ku thanks for that suggestion and the additional update. Here is some of my findings in case they help. I rebuilt the image with the latest commits and also enabled PREFER_AIRPLAY2 and what shows up matches what shows up in iOS. I am also now able to start and stop playback to the Office HomePods stereo pair unlike before. However there is some new odd behavior in that when I select either of the stereo HomePods connected to an Apple TV, the audio will play but the pair is not selected in the UI. The prompt for a pin for the Apple TV also shows up in the OwnTone UI. From here putting in the PIN does not seem to work and you are not able to de-select the HomePods from playback. I then built the image without the PREFER_AIRPLAY2 setting and when it loaded up you could see the individual HomePods selected in the UI once OwnTone started up. After I let that settle the AirPlay2 devices came back and I was now able to select the stereo pairs that are associated with the Apple TVs again. But then the error with the standalone stereo HomePods is back with the Office HomePods where it seems the AirPlay1 device is overwriting the AirPlay2 device. |
@shauder: I am sure there will be more of these quirks. The challenge now is to find all these API methods that somehow require mapping between one speaker and multiple devices. Pairing with a PIN is definitely one of these cases that needs special handling. For now only the toggling of the checkbox is supported. I need to setup my Apple TV for audio output to see if I can test that scenario. |
@ma-ku let me know if there is anything I can test or help with. Another behavior I will share that I found yesterday is this. Since the stand alone HomePod stereo pair was not working yesterday I did some further testing. Within the iOS Home app I moved the 'Office HomePods' stereo pair from my Office room to my bedroom room. I then set the 'Office HomePods' to the default audio output of the Apple TV in the bedroom. From there what I noticed is I was now able to select and control the 'Office HomePods' stereo pair from OwnTone but they now took on the name of the 'Bedroom Apple TV' instead of 'Office HomePods'. Then the 'Bedroom HomePods' that were no longer part of the 'Bedroom Apple TV' faced the same issue I was having with the Office HomePods when they were stand alone. Where the AirPlay1 device seems to overwrite/replace the grouped AirPlay2 device and cannot select it and initiate playback. |
Interesting. We should be careful with these observations as 15.4 might still be in flux. I have seen also quite a few quirks with speakers after the stereo group was dissolved. One speaker had to be reset and reinstalled before it was usable again. I will look into your findings. The best is always to provide the mDNS dump in these cases. Is the one above including the described behavior? Another question; did you update the code from GitHub or just recompile the version you had on your computer?� Might be that the latest is behaving a bit better. |
The mDNS above is when I set everything back to how it normally is with the Bedroom HomePods being default audio for the Bedroom Apple TV and the Office HomePods standalone in it's own room. If it's helpful, later I can move the Office HomePods back to the bedroom, set them as the default audio for the Bedroom Apple TV and then share what mDNS reports. |
I forgot to reply to your other question. All the recent testing today was with the latest code from your branch pulled and recompiled. |
I played with this a little today and if you select speakers for audio playback in Apple TV it comes down to be just another Airplay grouping (I refer to these groups as playback groups in the code). Technically it could dissolve into individual speakers at any time. One thing that I also saw is that for some reason the information about authentication requirements seem to get lost. I will need to check where and why. @ejurgensen: Have you checked the SETPEERS command? I am wondering if this is the magic key to tell speakers that they are in a group. Currently owntone just sets itself as the peer but in more complex setups you can see that the SETPEERS command sends all other speakers to one speaker. I have that on my list to check but its has a fairly low priority for now. |
Agree. I must admit that I do not want to make things overly complicated. It works nicely as-is so we should put it on a mental backlog for now. |
I have added PIN authentication and volume control for speaker groups to the branch. Feel free to test this version. To use the functionality, compile with the following symbols:
e.g. Technically it would also display speaker groups built in the Airplay panel. However, when playback to such a group is started from the web UI, the group 'magically' dissolves. Apparently there is more to group playback than just starting to stream to all members. |
@ma-ku - Thanks for the update. I have tested this and can confirm that it works as expected for my test scenario which is a stereo pair of original HomePods set as the default output for my Apple TV 4K. I will monitor the stability and performance of the system and report back any issues if they present. |
One issue I have found is that when using the api to select or deselect the speakers, the web UI does not reflect the changes. I have also seen a situation where after selecting the speakers from the web UI, the speaker is selected and works as expected however the UI updates a few moments later to show the speaker deselected. Would you want logs for these issues? |
Yes. Send those over. As I have already mentioned; I do not know all the different paths a function may get executed. So the API is not on my radar. I will see what I can do. |
Any news? Or should we commence to create PR for this? |
Sorry for the delay. Here are the logs. In this instance, only the owntone UI is used, when selecting the speaker (living room) the UI reports a 500 response code and does not show the speaker as selected however the speaker does play sound. It is not then possible to deselect the speaker as the UI always reports a 500 response code |
I updated my docker image (shauder/daapd:latest) and tested this too. I have 3 stereo pairs with two being connected to Apple TV's and then a Sonos roam. When I loaded up Owntone I could see them all (for some reason Office Stereo was grouped with the Sonos). I first tried the Living Room Stereo connected to the Apple TV and got the same 500 error but music played and the speaker showed disconnected. Then I did the Bedroom Stereo connected to the Apple TV and same thing. Then I did the Office Stereo grouped with the Sonos and they both started played and then showed ungrouped. At this point I had music played on all of them. I then deselected the Sonos and it stopped and then same for the Office Stereo. From there I just have music playing on the two connected to Apple TV's since I cannot deselect them.
The 500 error seems to be something with it wanting a PIN for the AppleTV but then it still manages to connect to the HomePods and play the music. |
I agree with @shauder, the 500 seems to be related to the pin request. So eventually the API still requires some work in that area. Just as an explanation what is going on behind the scenes; the mDNS scanning process finds potential groups and adds that information to the internal metadata about devices. Before the change, a device was also a speaker. The new change mangles that information on its way to the web in that way that instead of two speakers it now just returns one speaker with the group id. In the API, each call for a speaker is then dissolved into its corresponding devices and then executed. So far I have identified three calls where this is relevant; enable/disable a speaker, volume control, and pin pairing. Currently the code also tries to find grouped speakers (not stereo pairs) but for now this seems to be more complex than expected as these groups dissolve once owntone starts a playback to any of these speakers. So eventually I will turn that part off to make sure the stereo pairs are working correctly. |
I did some more testing and I was able to get the pin to show on the TV for both and pair them through the Owntone settings. For a while the living room would mostly work. Sometimes it would deselect and then I would select it again and it would stick. Then I could deselect and the sound would stop. The bedroom one seems to want me to pair it every time. Eventually the living room one wanted me to pair again too. Here is some more of the relevant logs.
|
Just a a couple of points I should have noted before. I have updated to the released 15.4 os for the HomePods. I initially paired with the pin code using the Owntone UI and the pin displayed on the Apple TV and that worked as expected. The speaker is selected/deselected correctly via the json api when called from curl. The issue seems to be in the UI. I will run another test and share the logs. |
Scratch that. I also get the same 500 response code from curl. This is different behaviour from last week when I was testing. |
When two Airplay speakers have been joined into a stereo pair, they still show up as two individual speakers. While playback of stereo streams seem to be working starting with audioOS 15.4 (see #1291), the UI still does not reflect the pairing and does not show the name of the stereo pair.
Expected behavior would be that instead of two speakers the UI would only show the stereo group with its name and eventually a visual clue that this is a stereo pair. When this pair is selected as output, then internally the server should stream content to the speakers involved in that group.
Initial work has been done on the backend in a forked repo. There, the parsing of the Airplay outputs is reflecting the grouping information found in mDNS and adds the information to the extended airplay record. It needs to be discussed, how the information is handled internally so that the UI can render the correct speaker information while the backend would need to know, which speakers are involved. Some guidance from @ejurgensen would be required to complete the work.
The text was updated successfully, but these errors were encountered: