punxaphil / maxi-media-player

Media card for Home Assistant UI with a focus on managing multiple media players, but not excluding single player setups.
7 stars 1 forks source link

Volume Change / Step / Mute not working for Single Player Mode #21

Closed thlucas1 closed 2 months ago

thlucas1 commented 2 months ago

Thought I would open a new issue for this, instead of commenting in the closed PR. Hope that's ok.

Checklist:

Release with the issue: v1.5.1 and prior

Last working release (if known): n/a

Browser and Operating System: Tried in both Google Chrome and Microsoft Edge - same results for both browsers.

Description of problem: I updated to v1.5.1 via HACS and restarted, but fix did not work - still no mute and no volume when using a single player. I verified that I removed the test script that I was using (as well as cleared cache), and it's using the /hacsfiles/maxi-media-player/maxi-media-player.js?hacstag=770072954150 resource.

The volume slider will move and stay to where I adjust it to, but a volume_set request is not passed on to the media_player. I have detailed tracing enabled in my SoundTouchPlus media player, and it is not receiving a volume set request. The mute button does not toggle nor receive a mute request either.

Here's the YAML I am using for the player:

type: custom:maxi-media-player
sections:
  - player
artworkAsBackground: true
showAudioInputFormat: true
playerVolumeOnlyAffectsMainPlayer: true
entities:
  - media_player.bose_st10_1
  - media_player.bose_st10_2
topFavorites:
  - ''
hideVolumeCogwheel: true
dontSwitchPlayerWhenGrouping: true

Here's a screenshot of what I see: image

Javascript errors shown in the web inspector (if applicable): n/a

Additional information:

After checking the above, I did some more testing ... I merged your changes into my main and test branch, and added some console.log() statements to the media-control-service.ts module i nvarious methods. Like so:

  async volumeSet(player: MediaPlayer, volume: number, updateMembers: boolean) {
    console.log("Maxi Player: volumeSet, player=" + player.name + ", volume=" + JSON.stringify(volume) + ", updateMembers=" + JSON.stringify(updateMembers))
    console.log("Maxi Player: volumeSet, player=" + player.name + ", members=" + JSON.stringify(player.members) + ", members.length=" + JSON.stringify(player.members.length))
   ...

  async setVolumeMute(mediaPlayer: MediaPlayer, muteVolume: boolean, updateMembers = true) {
    console.log("Maxi Player: setVolumeMute, player=" + mediaPlayer.name + ", muteVolume=" + JSON.stringify(muteVolume) + ", updateMembers=" + JSON.stringify(updateMembers))
    console.log("Maxi Player: setVolumeMute, player=" + mediaPlayer.name + ", members=" + JSON.stringify(mediaPlayer.members) + ", members.length=" + JSON.stringify(mediaPlayer.members.length))
   ...

Here's what I see in the console log when I execute a mute command:

# output when muting:
Maxi Player: setVolumeMute, player=Bose-ST10-1, muteVolume=true, updateMembers=true
Maxi Player: setVolumeMute, player=Bose-ST10-1, members=[], members.length=0

# output when unmuting:
Maxi Player: setVolumeMute, player=Bose-ST10-1, muteVolume=false, updateMembers=true
Maxi Player: setVolumeMute, player=Bose-ST10-1, members=[], members.length=0

Here's what I see in the console log when I execute a volume change command (using slider move):

# output when raising volume:
Maxi Player: volumeSet, player=Bose-ST10-1, volume=37, updateMembers=true
Maxi Player: volumeSet, player=Bose-ST10-1, members=[], members.length=0

# output when lowering volume:
Maxi Player: volumeSet, player=Bose-ST10-1, volume=15, updateMembers=true
Maxi Player: volumeSet, player=Bose-ST10-1, members=[], members.length=0

I also verified that the .js resource file had your current changes to the createGroupMembers method (compiled to the following):

createGroupMembers(e,t){const A=[];for(const i of st(e))for(const e of t)e.entity_id===i&&A.push(new wt(e,this.config));return null!=A?A:[this]}

It still appears that the player members array is empty when the volumeSet method is called.

I still think you need the if ((updateMembers) && (player.members.length > 0)) { logic in the media-control-service.ts \ volumeSet method - you only want to execute volumeSetGroup if you are updating multiple players AND there is at least 1 member in the group; or change the way you are calling the volumeSet method to use updateMembers = false.

For the calling of volumeSet method, it seems like the updateMembers value will always be true based upon a reference search of the method. In volume.ts, the @property({ type: Boolean }) updateMembers = true; value does not seem to change anywhere, and is always true, which causes the volumeSetGroup to always be executed in volumeSet method.

Here are my changes to media-control-service.ts that fix the issue (includes console.log messages if you want to test):

  private async volumeDefaultStep(mainPlayer: MediaPlayer, updateMembers: boolean, stepDirection: string) {
    console.log("Maxi Player: volumeDefaultStep, player=" + mainPlayer.name + ", updateMembers=" + JSON.stringify(updateMembers) + ", stepDirection=" + JSON.stringify(stepDirection))
    console.log("Maxi Player: volumeDefaultStep, player=" + mainPlayer.name + ", members=" + JSON.stringify(mainPlayer.members) + ", members.length=" + JSON.stringify(mainPlayer.members.length))
    if (mainPlayer.members.length == 0) {
      await this.hassService.callMediaService(stepDirection, { entity_id: mainPlayer.id });
    } else {
      for (const member of mainPlayer.members) {
        if (mainPlayer.id === member.id || updateMembers) {
          if (!member.ignoreVolume) {
            await this.hassService.callMediaService(stepDirection, { entity_id: member.id });
          }
        }
      }
    }
  }

  async volumeSet(player: MediaPlayer, volume: number, updateMembers: boolean) {
    console.log("Maxi Player: volumeSet, player=" + player.name + ", volume=" + JSON.stringify(volume) + ", updateMembers=" + JSON.stringify(updateMembers))
    console.log("Maxi Player: volumeSet, player=" + player.name + ", members=" + JSON.stringify(player.members) + ", members.length=" + JSON.stringify(player.members.length))
    if ((updateMembers) && (player.members.length > 0)) {
      return await this.volumeSetGroup(player, volume);
    } else {
      return await this.volumeSetSinglePlayer(player, volume);
    }
  }

  async setVolumeMute(mediaPlayer: MediaPlayer, muteVolume: boolean, updateMembers = true) {
    console.log("Maxi Player: setVolumeMute, player=" + mediaPlayer.name + ", muteVolume=" + JSON.stringify(muteVolume) + ", updateMembers=" + JSON.stringify(updateMembers))
    console.log("Maxi Player: setVolumeMute, player=" + mediaPlayer.name + ", members=" + JSON.stringify(mediaPlayer.members) + ", members.length=" + JSON.stringify(mediaPlayer.members.length))
    if (mediaPlayer.members.length == 0) {
      await this.hassService.callMediaService('volume_mute', { entity_id: mediaPlayer.id, is_volume_muted: muteVolume });
    } else {
      for (const member of mediaPlayer.members) {
        if (mediaPlayer.id === member.id || updateMembers) {
          await this.hassService.callMediaService('volume_mute', { entity_id: member.id, is_volume_muted: muteVolume });
        }
      }
    }
  }
punxaphil commented 2 months ago

My mistake, I forgot to check for zero length of members. Should be fixed here: v1.5.2

change: https://github.com/punxaphil/maxi-media-player/commit/c8665878445ad3b785638d29ea0953a57a501cad

thlucas1 commented 2 months ago

Works good - thanks!