home-assistant / core

:house_with_garden: Open source home automation that puts local control and privacy first.
https://www.home-assistant.io
Apache License 2.0
73.04k stars 30.55k forks source link

tts to the sonos group only via one loudspeaker #92637

Closed christianeuropa closed 1 year ago

christianeuropa commented 1 year ago

The problem

If I group three loudspeakers and send the tts service to the "master speaker", the TTS is only played there and not by the whole group

What version of Home Assistant Core has the issue?

core-2023.5.1

What was the last working version of Home Assistant Core?

core-2023.4

What type of installation are you running?

Home Assistant OS

Integration causing the issue

sonos

Link to integration documentation on our website

https://www.home-assistant.io/integrations/sonos

Diagnostics information

No response

Example YAML snippet

No response

Anything in the logs that might be useful for us?

No response

Additional information

No response

home-assistant[bot] commented 1 year ago

Hey there @cgtobi, @jjlawren, mind taking a look at this issue as it has been labeled with an integration (sonos) you are listed as a code owner for? Thanks!

Code owner commands Code owners of `sonos` can trigger bot actions by commenting: - `@home-assistant close` Closes the issue. - `@home-assistant rename Awesome new title` Renames the issue. - `@home-assistant reopen` Reopen the issue. - `@home-assistant unassign sonos` Removes the current integration label and assignees on the issue, add the integration domain after the command.

(message by CodeOwnersMention)


sonos documentation sonos source (message by IssueLinks)

jjlawren commented 1 year ago

This is a side-effect of the new announce feature added in 2023.5. It uses a new method which targets individual speakers (not groups) for announcements/TTS where a snapshot/restore is no longer needed if audio is currently playing.

You can play on multiple speakers simultaneously by adding a list of media_player entities/devices to the call. Note that you do not need to group speakers to use it in this manner anymore.

However your example is about speakers that are normally "invisible" to the integration. This is likely fixable, but would require new development.

christianeuropa commented 1 year ago

Thank you for the explanation. Unfortunately, I haven't found an example of how to implement the new function with tts. I use the service tts.amazon_polly_say and I can't set an announce to true.

jjlawren commented 1 year ago

You don't need to, the TTS service calls do that automatically under the hood.

heyitsyang commented 1 year ago

I'm seeing the same thing. My normal scripts that join/unjoin speakers based on conditions no longer work. However, if I use the Developer Tools and play media through the "master" speaker in a joined group, the group still works as expected.

In perusing the release notes, I don't see anything about a new announce feature being added in 2023.5. Can you please point me in the right direction or an example?

Sonos synchronizes media so all of the grouped speakers play as if one - without lagging sound in one speaker or another. Will this new way of addressing speakers individually be in a likewise synchronized manner?

heyitsyang commented 1 year ago

OK I see the announce option in media players, but the problem described here seems like it should be unrelated. The announce function should only make the snapshot redundant but it is also affecting the grouping behavior.

Here's what I see:

I have three Sonos speakers. there a two paired as a stereo set called "main speakers". I have a third in an office/bedroom called "office speaker". The office speaker is normally joined with the main speakers and gets unjoined when a guest input_boolean is set.

If I have main & office speakers joined in a group, I can play media using the ( i ) below the media_player,main_speakers in Developer Tools>States and the speakers work in a joined group as expected.

If run the following yaml in Developer Tools>Services, it only plays from the Sonos main speakers and not the joined office speaker.

service: tts.google_translate_say
data:
  entity_id: 
    - media_player.main_speakers
  message: "This is a test message"
jjlawren commented 1 year ago

With the new announce behavior, the grouping used for music playback is no longer tied to alerts/TTS. You explicitly say which speakers/rooms should play the announcement without needing to know the current grouping. All of these services can accept multiple entities/devices in a single call.

For example, if you're playing music in rooms A, B, and D, you're now able to play an alert in B and C without regrouping or interrupting existing music playback.

christianeuropa commented 1 year ago

I have now solved an announcement as follows:

service: tts.amazon_polly_say
data:
  cache: false
  entity_id: media_player.bad , media_player.wohnzimmer
  message: We can have breakfast

But how can I make this announcement happen at a higher volume? I cannot set the volume option.

jjlawren commented 1 year ago

But how can I make this announcement happen at a higher volume? I cannot set the volume option.

This is a common question and I've suggested an update to the docs. You can use a special TTS Media Source url such as this:

service: media_player.play_media
data:
  announce: true
  entity_id: media_player.bad, media_player.wohnzimmer
  media_content_id: media-source://tts/amazon_polly?message="I am very loud"
  media_content_type: music
  extra:
    volume: 80
heyitsyang commented 1 year ago

How are independent volumes set? This example seems to assume that every speaker in the list will use the same volume. In my case, the room size makes a difference on where I need to set the volume.

jjlawren commented 1 year ago

How are independent volumes set? This example seems to assume that every speaker in the list will use the same volume. In my case, the room size makes a difference on where I need to set the volume.

You'd make a separate call per volume level in that case.

heyitsyang commented 1 year ago

Wouldn't the speech no longer be synchronized across speakers? Without synchronization, speakers in separate rooms (open floor plan), but within earshot of another would be sound like echoes. IMHO this is a significant loss in functionality and spousal approval factor.

jjlawren commented 1 year ago

Wouldn't the speech no longer be synchronized across speakers? Without synchronization, speakers in separate rooms (open floor plan), but within earshot of another would be sound like echoes. IMHO this is a significant loss in functionality and spousal approval factor.

You're free to use the old method (announce: false) if precise multi-room audio sync for announcements is your primary concern. It will behave like it did previous to 2023.5. However this requires complex regrouping/snapshotting in scripts/automations and resuming does not work this way with several music sources.

The new default behavior prioritizes simplicity and improved user experience by not interrupting music playback.

heyitsyang commented 1 year ago

Thanks for your help. Though the old method brings me back around to the problem the OP described. I think I can work past it by creating a template sensor that provides the logic for the proper list of speakers under various conditions.

It would be useful to have these side affects mentioned under breaking changes in the future. Thanks again.

heyitsyang commented 1 year ago

Well, it turns out I cant; use a template sensor as the _entityid: can't accept templates. It would be nice if the extras: volume: would accept a list of media_players and volumes. Otherwise you're right in that the code gets cumbersome.

heyitsyang commented 1 year ago

I've re-written my code to accommodate the method in your example addressing the speaker without using the Sonos Joiin/UnJoin. The difference is that the new method introduces a delay so that the speakers are no longer synchronized.

Is it possible to re-open this issue and loop in the author of the Sonos integration?

jjlawren commented 1 year ago

Your issue is unrelated to this one, so this should not be reopened.

Audio sync between speakers for announcements is not guaranteed like standard music playback. It's a separate API that (as far as we can tell) only targets individual speakers. As mentioned before, if audio sync is your highest priority, the non-announce playback methods are still available.

heyitsyang commented 1 year ago

I know you'd like to move on, but please be patient and stay with me on this issue.

I think it is related, but I don't know enough about the inner workings to untangle it. But just to be clear, let me summarize the conversation:

We are left with one of the following mutually exclusive choices:

  1. sound volumes that are not appropriate for individual rooms OR
  2. individual calls that break the Sonos' sound synchronization.

Do I have this right? Is there some other method that I'm missing?

jjlawren commented 1 year ago

Using announce: false doesn't allow the old method to work.

The new announcement API call is only made when announce: true in calls to media_player.play_media. If unset orfalse` it will act exactly like it did in older versions.

If you're using tts.*_say, these will automatically set announce. However you can use a special play_media call to bypass this:

service: media_player.play_media
target:
  entity_id: media_player.sonos
data:
  announce: false
  media_content_id: >
    media-source://tts/cloud?message="say something"
  media_content_type: "music"

(Setting announce to false is not necessary but used for illustration.)

The new announce feature uses a different Sonos API that only addresses a single speaker. You can either have perfectly synced audio alerts across multiple speakers or you can have a better announcement experience, not both.

heyitsyang commented 1 year ago

If unset or false` it will act exactly like it did in older versions.

My point is this statement is not true. If announce->false, the volume of the announce is at the volume of the media stream being interrupted. If music is being played at a loud level and it is interrupted by an announcement, it will be at the volume of the loud music. In the previous method, the volume could be set for each individual speaker for the announcement and return to the music at its own level.

So unless I'm missing something, the old API no longer works with joined speakers (requires speakers to be indivually adddressed), but the new API cannot be made to work like the old because it doesn't have individual per speaker volume settings when announce->true and only announces at the current streaming volume if announce-> false.

jjlawren commented 1 year ago

Previous to 2023.5, volume control was always decoupled from play_media calls--it was required to use set_volume yourself (before and after). This has not changed if you disable announce. The extra->volume parameter is only used when announce is enabled, and only on 2023.5+.

heyitsyang commented 1 year ago

Does this also break the L+R pairing of Sonos speakers? I have a paired set (L+R) that appears as one virtual speaker to HA. I just noticed it also only plays from one speaker now. But I've been doing so many tests that I could have it in some buggered state.

jjlawren commented 1 year ago

Yes, as of now it will play on the soundbar in a home theater setup or the left speaker in a stereo pair. I think I'll try to adjust this to play on all in the future.

heyitsyang commented 1 year ago

+1 and +1 on independent volume controls in extras->volume

Thanks for all your work.

jjlawren commented 1 year ago

+1 and +1 on independent volume controls in extras->volume

This API can only address a single speaker at a time, as it sends the command to each speaker directly and independently. Individual volume controls can be achieved using multiple calls to media_player.play_media with different parameters. Anything done in the integration would just be making multiple calls behind the scenes anyway.

heyitsyang commented 1 year ago

Is it possible to leave the old API as it was or offer an alternative so that multiple speakers can be used. I could then just go back to my old code which was more flexible.

jjlawren commented 1 year ago

As mentioned before, the old playback method is still used when announce is not set.

If you have an example where this is not working, share it in a new issue.