@@ -1066,7 +1066,23 @@ def _translate_members_to_remove_for_protocols(
10661066 protocol_members .append (child_protocol .output_protocol_id )
10671067 continue
10681068
1069- native_members .append (child_player_id )
1069+ # Check if child's protocol player is in parent's native group_members
1070+ # This handles native protocol players (e.g., native AirPlay player like Apple TV)
1071+ # where the parent itself contains protocol player IDs in its group_members
1072+ translated = False
1073+ for linked in child_player .linked_output_protocols :
1074+ if linked .output_protocol_id in parent_player .group_members :
1075+ self .logger .debug (
1076+ "Translating removal (native parent): %s -> protocol %s" ,
1077+ child_player_id ,
1078+ linked .output_protocol_id ,
1079+ )
1080+ native_members .append (linked .output_protocol_id )
1081+ translated = True
1082+ break
1083+
1084+ if not translated :
1085+ native_members .append (child_player_id )
10701086
10711087 return protocol_members , native_members
10721088
@@ -1119,13 +1135,15 @@ def _try_child_preferred_protocol(
11191135 if not child_protocol or not child_protocol .available :
11201136 return None , None
11211137
1122- # Check if parent supports this protocol
1123- parent_protocol = parent_player .get_linked_protocol (child_protocol .protocol_domain )
1138+ # Check if parent supports this protocol (including native protocol)
1139+ parent_protocol = parent_player .get_output_protocol_by_domain (
1140+ child_protocol .protocol_domain
1141+ )
11241142 if not parent_protocol or not parent_protocol .available :
11251143 return None , None
11261144
11271145 # Check if this protocol supports set_members
1128- protocol_player = self . get_player (parent_protocol .output_protocol_id )
1146+ protocol_player = parent_player . get_protocol_player (parent_protocol .output_protocol_id )
11291147 if (
11301148 not protocol_player
11311149 or PlayerFeature .SET_MEMBERS not in protocol_player .state .supported_features
@@ -1165,7 +1183,9 @@ def _try_find_common_protocol(
11651183 )
11661184 if not child_protocol or not child_protocol .available :
11671185 continue
1168- protocol_player = self .get_player (parent_output_protocol .output_protocol_id )
1186+ protocol_player = parent_player .get_protocol_player (
1187+ parent_output_protocol .output_protocol_id
1188+ )
11691189 if (
11701190 protocol_player
11711191 and PlayerFeature .SET_MEMBERS in protocol_player .state .supported_features
@@ -1231,9 +1251,11 @@ def _translate_members_for_protocols(
12311251 and (not parent_protocol_domain or protocol_domain == parent_protocol_domain )
12321252 ):
12331253 if not parent_protocol_player or parent_protocol_domain != protocol_domain :
1234- parent_protocol = parent_player .get_linked_protocol (protocol_domain )
1254+ parent_protocol = parent_player .get_output_protocol_by_domain (protocol_domain )
12351255 if parent_protocol :
1236- parent_protocol_player = self .get_player (parent_protocol .output_protocol_id )
1256+ parent_protocol_player = parent_player .get_protocol_player (
1257+ parent_protocol .output_protocol_id
1258+ )
12371259 parent_protocol_domain = protocol_domain
12381260 protocol_members .append (child_protocol_id )
12391261 self .logger .log (
@@ -1290,7 +1312,9 @@ def _translate_members_for_protocols(
12901312 not parent_protocol_player
12911313 or parent_protocol_domain != parent_protocol .protocol_domain
12921314 ):
1293- parent_protocol_player = self .get_player (parent_protocol .output_protocol_id )
1315+ parent_protocol_player = parent_player .get_protocol_player (
1316+ parent_protocol .output_protocol_id
1317+ )
12941318 if parent_protocol_player :
12951319 parent_protocol_domain = parent_protocol_player .provider .domain
12961320 protocol_members .append (child_protocol .output_protocol_id )
@@ -1365,28 +1389,55 @@ async def _forward_protocol_set_members(
13651389 player_ids_to_remove = filtered_protocol_remove or None ,
13661390 )
13671391
1392+ # Set active output protocol on added child players
1393+ if filtered_protocol_add :
1394+ for child_protocol_id in filtered_protocol_add :
1395+ if child_protocol := self .get_player (child_protocol_id ):
1396+ if child_protocol .protocol_parent_id :
1397+ if child_player := self .get_player (child_protocol .protocol_parent_id ):
1398+ if child_player .active_output_protocol != child_protocol_id :
1399+ self .logger .debug (
1400+ "Setting active output protocol on child %s to %s" ,
1401+ child_player .state .name ,
1402+ child_protocol_id ,
1403+ )
1404+ child_player .set_active_output_protocol (child_protocol_id )
1405+
13681406 # If we added members via this protocol, set it as the active output protocol
1369- # and restart playback if currently playing
1370- if (
1371- filtered_protocol_add
1372- and parent_player .active_output_protocol != parent_protocol_player .player_id
1373- ):
1407+ # and restart playback if currently playing AND we're switching protocols
1408+ if filtered_protocol_add :
13741409 previous_protocol = parent_player .active_output_protocol
13751410 was_playing = parent_player .state .playback_state == PlaybackState .PLAYING
13761411
1412+ # Determine if we're switching protocols (which requires restart)
1413+ # Native protocol: parent_protocol_player is the same as parent_player
1414+ is_native_protocol = parent_protocol_player .player_id == parent_player .player_id
1415+ already_using_native = previous_protocol in (None , "native" )
1416+ already_using_this_protocol = previous_protocol == parent_protocol_player .player_id
1417+
1418+ # Only restart if we're actually switching to a different protocol
1419+ switching_protocols = not (
1420+ (is_native_protocol and already_using_native ) or already_using_this_protocol
1421+ )
1422+
13771423 self .logger .debug (
1378- "Setting active output protocol to %s after grouping members "
1379- "(previous: %s, was_playing: %s)" ,
1380- parent_protocol_player .player_id ,
1381- previous_protocol ,
1424+ "Protocol grouping: is_native=%s, already_native=%s, already_this=%s, "
1425+ "switching=%s, was_playing=%s" ,
1426+ is_native_protocol ,
1427+ already_using_native ,
1428+ already_using_this_protocol ,
1429+ switching_protocols ,
13821430 was_playing ,
13831431 )
1384- parent_player .set_active_output_protocol (parent_protocol_player .player_id )
13851432
1386- # Restart playback on the new protocol if we were playing
1387- if was_playing :
1433+ # Update active output protocol if not already using native
1434+ if not (is_native_protocol and already_using_native ):
1435+ parent_player .set_active_output_protocol (parent_protocol_player .player_id )
1436+
1437+ # Restart playback only if we're switching protocols
1438+ if was_playing and switching_protocols :
13881439 self .logger .info (
1389- "Restarting playback on %s via %s protocol after grouping members " ,
1440+ "Restarting playback on %s via %s protocol after switching protocols " ,
13901441 parent_player .state .name ,
13911442 parent_protocol_player .provider .domain ,
13921443 )
0 commit comments