sub sonos_upnp_update { my ($service, %properties) = @_; Log (2, "Event received for service=" . $service->{BASE} . " id = " . $service->serviceId); # Log(4, Dumper(\%properties)); # Save off the zone names if ($service->serviceId =~ /serviceId:ZoneGroupTopology/) { foreach my $key (keys %properties) { if ($key eq "ZoneGroupState") { my $tree = XMLin(decode_entities($properties{$key}), forcearray => ["ZoneGroup", "ZoneGroupMember"]); Log(4, "ZoneGroupTopology " . Dumper($tree)); foreach my $group (@{$tree->{ZoneGroup}}) { my %zonegroup = %{$group}; foreach my $member (@{$zonegroup{ZoneGroupMember}}) { my $zkey = $member->{UUID}; foreach my $mkey (keys %{$member}) { $main::ZONES{$zkey}->{$mkey} = $member->{$mkey}; } $main::ZONES{$zkey}->{Coordinator} = $zonegroup{Coordinator}; my @ip = split(/\//, $member->{Location}); $main::ZONES{$zkey}->{IPPORT} = $ip[2]; $main::ZONES{$zkey}->{AV}->{LASTUPDATE} = 1 if (!defined $main::ZONES{$zkey}->{AV}->{LASTUPDATE}); $main::ZONES{$zkey}->{RENDER}->{LASTUPDATE} = 1 if (!defined $main::ZONES{$zkey}->{RENDER}->{LASTUPDATE}); $main::ZONES{$zkey}->{AV}->{CurrentTrackMetaData} = "" if (!defined $main::ZONES{$zkey}->{AV}->{CurrentTrackMetaData}); $main::QUEUEUPDATE{$zkey} = 1 if (!defined $main::QUEUEUPDATE{$zkey}); } } $main::LASTUPDATE = $main::SONOS_UPDATENUM; $main::ZONESUPDATE = $main::SONOS_UPDATENUM++; sonos_process_waiting("ZONES"); } elsif ($key eq "ThirdPartyMediaServers") { my $tree = XMLin(decode_entities($properties{$key}), forcearray => ["Service"]); for my $item ( @{ $tree->{Service} } ) { if($item->{UDN} =~ "SA_RINCON1_") { #Rhapsody Log(2, "Adding Rhapsody Subscription"); $main::SERVICES{Rhapsody} = $item; } elsif($item->{UDN} =~ "SA_RINCON4_") { #PANDORA Log(2, "Adding Pandora Subscription"); $main::SERVICES{Pandora} = $item; } elsif($item->{UDN} =~ "SA_RINCON6_") { #SIRIUS Log(2, "Adding Sirius Subscription"); $main::SERVICES{Sirius} = $item; } } sonos_process_waiting("SERVICES"); } else { Log(4, "$key " . Dumper($properties{$key})); } } } my $zone = sonos_location_to_id($service->{BASE}); # Save off the current status if ($service->serviceId =~ /serviceId:RenderingControl/) { if (decode_entities($properties{LastChange}) eq "") { Log(3, "Unknown RenderingControl " . Dumper(\%properties)); return; } my $tree = XMLin(decode_entities($properties{LastChange}), forcearray => ["ZoneGroup"], keyattr=>{"Volume" => "channel", "Mute" => "channel", "Loudness" => "channel"}); Log(4, "RenderingControl " . Dumper($tree)); foreach my $key ("Volume", "Treble", "Bass", "Mute", "Loudness") { if ($tree->{InstanceID}->{$key}) { $main::ZONES{$zone}->{RENDER}->{$key} = $tree->{InstanceID}->{$key}; $main::LASTUPDATE = $main::SONOS_UPDATENUM; $main::ZONES{$zone}->{RENDER}->{LASTUPDATE} = $main::SONOS_UPDATENUM++; } } sonos_process_waiting("RENDER", $zone); return; } if ($service->serviceId =~ /serviceId:AVTransport/) { if (decode_entities($properties{LastChange}) eq "") { Log(3, "Unknown AVTransport " . Dumper(\%properties)); return; } my $tree = XMLin(decode_entities($properties{LastChange})); Log(4, "AVTransport " . Dumper($tree)); foreach my $key ("CurrentTrackMetaData", "CurrentPlayMode", "NumberOfTracks", "CurrentTrack", "TransportState", "AVTransportURIMetaData", "AVTransportURI", "r:NextTrackMetaData", "CurrentTrackDuration") { if ($tree->{InstanceID}->{$key}) { $main::LASTUPDATE = $main::SONOS_UPDATENUM; $main::ZONES{$zone}->{AV}->{LASTUPDATE} = $main::SONOS_UPDATENUM++; if ($tree->{InstanceID}->{$key}->{val} =~ /^</) { $tree->{InstanceID}->{$key}->{val} = decode_entities($tree->{InstanceID}->{$key}->{val}); } if ($tree->{InstanceID}->{$key}->{val} =~ /^{AV}->{$key} = \%{XMLin($tree->{InstanceID}->{$key}->{val})}; } else { $main::ZONES{$zone}->{AV}->{$key} = $tree->{InstanceID}->{$key}->{val}; } } } sonos_process_waiting("AV", $zone); return; } if ($service->serviceId =~ /serviceId:ContentDirectory/) { Log(4, "ContentDirectory " . Dumper(\%properties)); if (defined $properties{ContainerUpdateIDs} && $properties{ContainerUpdateIDs} =~ /AI:/) { sonos_containers_del("AI:"); } if (!defined $main::ZONES{$zone}->{QUEUE} || $properties{ContainerUpdateIDs} =~ /Q:0/) { Log (2, "Refetching Q for $main::ZONES{$zone}->{ZoneName} updateid $properties{ContainerUpdateIDs}"); $main::ZONES{$zone}->{QUEUE} = upnp_content_dir_browse($zone, "Q:0"); $main::LASTUPDATE = $main::SONOS_UPDATENUM; $main::QUEUEUPDATE{$zone} = $main::SONOS_UPDATENUM++; sonos_process_waiting("QUEUE", $zone); } if (defined $properties{ShareIndexInProgress}) { $main::UPDATEID{ShareIndexInProgress} = $properties{ShareIndexInProgress}; } if (defined $properties{MasterRadioUpdateID} && ($properties{MasterRadioUpdateID} ne $main::UPDATEID{MasterRadioUpdateID})) { $main::UPDATEID{MasterRadioUpdateID} = $properties{MasterRadioUpdateID}; sonos_containers_del("R:"); } if (defined $properties{SavedQueuesUpdateID} && $properties{SavedQueuesUpdateID} ne $main::UPDATEID{SavedQueuesUpdateID}) { $main::UPDATEID{SavedQueuesUpdateID} = $properties{SavedQueuesUpdateID}; sonos_containers_del("SQ:"); } if (defined $properties{ShareListUpdateID} && $properties{ShareListUpdateID} ne $main::UPDATEID{ShareListUpdateID}) { $main::UPDATEID{ShareListUpdateID} = $properties{ShareListUpdateID}; Log (2, "Refetching Index, update id $properties{ShareListUpdateID}"); add_timeout (time(), \&sonos_fetch_music); } return; } while (my ($key, $val) = each %properties) { if ($val =~ /</) { my $d = decode_entities($val); my $tree = XMLin($d, forcearray => ["ZoneGroup"], keyattr=>{"ZoneGroup" => "ID"}); Log(3, "Property ${key}'s value is " . Dumper($tree)); } else { Log(3, "Property ${key}'s value is " . $val); } } }