Skip to content

Commit bd1983b

Browse files
author
tobexyz
committed
chore: fixed renderer service
1 parent 216c966 commit bd1983b

10 files changed

Lines changed: 192 additions & 57 deletions

yaacc/src/main/java/de/yaacc/player/LocalMediaSessionPlayer.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public void onMediaItemTransition(@Nullable MediaItem mediaItem, int reason) {
109109
);
110110

111111
mediaSession = new MediaSession.Builder(getContext(), exoPlayer)
112-
.setId("local_audio_" + getId())
112+
.setId("local_audio_" + getId() + "_" + System.currentTimeMillis())
113113
.setSessionActivity(sessionActivity)
114114
.build();
115115

@@ -235,20 +235,25 @@ protected void startItem(PlayableItem playableItem, Object loadedItem, int index
235235
pendingIndex = index;
236236
return;
237237
}
238-
if (exoPlayer.getMediaItemCount() != getItems().size()) {
239-
setItems(getItems().toArray(new PlayableItem[0]));
240-
}
238+
241239
DIDLObject.Property<URI> albumArtUriProperty = playableItem.getItem() == null ? null :
242240
playableItem.getItem().getFirstProperty(DIDLObject.Property.UPNP.ALBUM_ART_URI.class);
243241
albumArtUri = (albumArtUriProperty == null) ? null : albumArtUriProperty.getValue();
244242

245-
// ExoPlayer must be called from main thread
243+
// Notify listeners that track changed (for UI updates)
244+
firePropertyChange(PROPERTY_ITEM, null, playableItem);
245+
246+
// ExoPlayer must be called from main thread - move ALL ExoPlayer access inside Handler
246247
new Handler(Looper.getMainLooper()).post(() -> {
247-
if (exoPlayer != null) {
248-
exoPlayer.setPlayWhenReady(true);
249-
exoPlayer.seekTo(index, 0);
250-
exoPlayer.prepare();
251-
exoPlayer.play();
248+
ExoPlayer player = exoPlayer; // Store local reference to avoid race condition
249+
if (player != null) {
250+
if (player.getMediaItemCount() != getItems().size()) {
251+
setItems(getItems().toArray(new PlayableItem[0]));
252+
}
253+
player.setPlayWhenReady(true);
254+
player.seekTo(index, 0);
255+
player.prepare();
256+
player.play();
252257
setPlaying(true);
253258
showNotificationInternal(); // Show notification
254259
YaaccLogger.d(getClass().getName(), "Started playing: " + playableItem.getTitle());

yaacc/src/main/java/de/yaacc/upnp/UpnpClient.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,7 @@ public List<Player> initializePlayers(AvTransport transport) {
786786
List<Item> metadataItems = metadata.getItems();
787787
for (Item item : metadataItems) {
788788
playableItem.setTitle(item.getTitle());
789+
playableItem.setItem(item); // Store the DIDL item for album art and other metadata
789790
List<Res> metadataResources = item.getResources();
790791
for (Res res : metadataResources) {
791792
if (res.getProtocolInfo() != null) {

yaacc/src/main/java/de/yaacc/upnp/server/YaaccUpnpServerService.java

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,11 @@
8080

8181
import de.yaacc.R;
8282
import de.yaacc.Yaacc;
83+
import de.yaacc.upnp.UpnpClient;
8384
import de.yaacc.upnp.protocol.UpnpProtocolHandler;
8485
import de.yaacc.upnp.registry.Registry;
8586
import de.yaacc.upnp.registry.RegistryImpl;
87+
import de.yaacc.upnp.server.avtransport.AvTransport;
8688
import de.yaacc.upnp.server.avtransport.YaaccAVTransportService;
8789
import de.yaacc.upnp.server.configuration.YaaccUpnpServerControlActivity;
8890
import de.yaacc.util.SAFCacheManager;
@@ -515,20 +517,65 @@ private void createUpnpDevice() {
515517

516518

517519
List<LocalService<?>> services = new ArrayList();
518-
519520
services.addAll(Arrays.asList(createCoreServices()));
520-
if (preferences.getBoolean(getApplicationContext().getString(R.string.settings_local_server_chkbx), false)) {
521-
if (preferences.getBoolean(getApplicationContext().getString(R.string.settings_local_server_provider_chkbx), false)) {
521+
522+
boolean serverEnabled = preferences.getBoolean(getApplicationContext().getString(R.string.settings_local_server_chkbx), false);
523+
boolean providerEnabled = preferences.getBoolean(getApplicationContext().getString(R.string.settings_local_server_provider_chkbx), false);
524+
boolean rendererEnabled = preferences.getBoolean(getApplicationContext().getString(R.string.settings_local_server_receiver_chkbx), false);
525+
526+
DeviceIdentity identity = new DeviceIdentity(new UDN(locaDeviceUuid));
527+
528+
// If both server and renderer are enabled, create embedded devices
529+
if (serverEnabled && providerEnabled && rendererEnabled) {
530+
// Create services once
531+
LocalService<?>[] serverServices = createMediaServerServices();
532+
LocalService<?>[] rendererServices = createMediaRendererServices();
533+
534+
// Create embedded MediaServer device
535+
LocalDevice serverDevice = new LocalDevice(
536+
new DeviceIdentity(new UDN(locaDeviceUuid + "-server")),
537+
new UDADeviceType("MediaServer"),
538+
yaaccDetails,
539+
createDeviceIcons(),
540+
serverServices
541+
);
542+
543+
// Create embedded MediaRenderer device
544+
LocalDevice rendererDevice = new LocalDevice(
545+
new DeviceIdentity(new UDN(locaDeviceUuid + "-renderer")),
546+
new UDADeviceType("MediaRenderer"),
547+
yaaccDetails,
548+
createDeviceIcons(),
549+
rendererServices
550+
);
551+
552+
// Create root device with embedded devices (core services only in root)
553+
localDevice = new LocalDevice(
554+
identity,
555+
new UDADeviceType("Basic", 1),
556+
yaaccDetails,
557+
createDeviceIcons(),
558+
services.toArray(new LocalService<?>[0]),
559+
new LocalDevice[]{serverDevice, rendererDevice}
560+
);
561+
} else {
562+
// Single device type
563+
if (serverEnabled && providerEnabled) {
522564
services.addAll(Arrays.asList(createMediaServerServices()));
523-
524-
525565
}
526-
if (preferences.getBoolean(getApplicationContext().getString(R.string.settings_local_server_receiver_chkbx), false)) {
566+
if (serverEnabled && rendererEnabled) {
527567
services.addAll(Arrays.asList(createMediaRendererServices()));
528568
}
569+
570+
UDADeviceType deviceType;
571+
if (rendererEnabled && !providerEnabled) {
572+
deviceType = new UDADeviceType("MediaRenderer");
573+
} else {
574+
deviceType = new UDADeviceType("MediaServer");
575+
}
576+
577+
localDevice = new LocalDevice(identity, deviceType, yaaccDetails, createDeviceIcons(), services.toArray(new LocalService<?>[0]));
529578
}
530-
DeviceIdentity identity = new DeviceIdentity(new UDN(locaDeviceUuid));
531-
localDevice = new LocalDevice(identity, new UDADeviceType("MediaServer"), yaaccDetails, createDeviceIcons(), services.toArray(new LocalService<?>[0]));
532579
registry.addDevice(localDevice);
533580

534581
// Configure ALIVE announcement interval from settings
@@ -763,6 +810,7 @@ private LocalService<?>[] createCoreServices() {
763810
*/
764811
private LocalService<?>[] createMediaRendererServices() {
765812
List<LocalService<?>> services = new ArrayList<>();
813+
services.add(createConnectionManagerService());
766814
services.add(createAVTransportService());
767815
services.add(createRenderingControl());
768816
return services.toArray(new LocalService[]{});
@@ -799,6 +847,12 @@ protected YaaccContentDirectory createServiceInstance() {
799847
*/
800848
@SuppressWarnings("unchecked")
801849
private LocalService<YaaccAVTransportService> createAVTransportService() {
850+
// Set upnpClient for state classes to access (may be null during initialization)
851+
UpnpClient client = ((Yaacc) getApplicationContext()).getUpnpClient();
852+
if (client != null) {
853+
AvTransport.setUpnpClient(client);
854+
}
855+
802856
LocalService<YaaccAVTransportService> avTransportService = new AnnotationLocalServiceBinder().read(YaaccAVTransportService.class);
803857
avTransportService.setManager(new DefaultServiceManager<>(avTransportService, null) {
804858
@Override

yaacc/src/main/java/de/yaacc/upnp/server/avtransport/AvTransport.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,26 @@
2222
import org.fourthline.cling.support.model.AVTransport;
2323
import org.fourthline.cling.support.model.StorageMedium;
2424

25+
import de.yaacc.upnp.UpnpClient;
26+
2527

2628
/**
2729
* @author Tobias Schoene (TheOpenBit)
2830
*/
2931
public class AvTransport extends AVTransport {
3032

33+
private static UpnpClient upnpClient;
34+
3135
public AvTransport(UnsignedIntegerFourBytes instanceID, LastChange lastChange, StorageMedium possiblePlayMedium) {
3236
super(instanceID, lastChange, possiblePlayMedium);
3337
}
3438

39+
public static void setUpnpClient(UpnpClient client) {
40+
upnpClient = client;
41+
}
42+
43+
public static UpnpClient getUpnpClient() {
44+
return upnpClient;
45+
}
46+
3547
}

yaacc/src/main/java/de/yaacc/upnp/server/avtransport/AvTransportMediaRendererNoMediaPresent.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,8 @@ public class AvTransportMediaRendererNoMediaPresent extends
4141
* Constructor.
4242
*
4343
* @param transport the state holder
44-
* @param upnpClient the upnpClient to use
4544
*/
46-
public AvTransportMediaRendererNoMediaPresent(AvTransport transport,
47-
UpnpClient upnpClient) {
45+
public AvTransportMediaRendererNoMediaPresent(AvTransport transport) {
4846
super(transport);
4947
}
5048

yaacc/src/main/java/de/yaacc/upnp/server/avtransport/AvTransportMediaRendererPaused.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,10 @@ public class AvTransportMediaRendererPaused extends PausedPlay<AvTransport> impl
4444
* Constructor.
4545
*
4646
* @param transport the state holder
47-
* @param upnpClient the upnpclient to use
4847
*/
49-
public AvTransportMediaRendererPaused(AvTransport transport,
50-
UpnpClient upnpClient) {
48+
public AvTransportMediaRendererPaused(AvTransport transport) {
5149
super(transport);
52-
this.upnpClient = upnpClient;
50+
this.upnpClient = AvTransport.getUpnpClient();
5351
}
5452

5553
/* (non-Javadoc)

yaacc/src/main/java/de/yaacc/upnp/server/avtransport/AvTransportMediaRendererPlaying.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,10 @@ public class AvTransportMediaRendererPlaying extends Playing<AvTransport> implem
5353
* Constructor.
5454
*
5555
* @param transport the state holder
56-
* @param upnpClient the upnpclient to use
5756
*/
58-
public AvTransportMediaRendererPlaying(AvTransport transport,
59-
UpnpClient upnpClient) {
57+
public AvTransportMediaRendererPlaying(AvTransport transport) {
6058
super(transport);
61-
this.upnpClient = upnpClient;
59+
this.upnpClient = AvTransport.getUpnpClient();
6260
}
6361

6462
/*
@@ -211,14 +209,24 @@ private void setTrackInfo() {
211209

212210
private void doSetTrackInfo() {
213211
for (Player player : players) {
214-
if (player != null && !player.getDuration().equals("")) {
215-
getTransport().getPositionInfo().setTrackDuration(player.getDuration());
216-
getTransport().getPositionInfo().setRelTime(player.getElapsedTime());
217-
YaaccLogger.d(getClass().getName(), "doSetTrackInfo: " + getTransport() + "Posinfo:" + getTransport().getPositionInfo() + " RelTime: " + getTransport().getPositionInfo().getRelTime());
212+
if (player != null) {
213+
// Get duration on main thread for Media3 compatibility
214+
final String[] duration = {""};
215+
final String[] elapsedTime = {""};
216+
217+
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
218+
duration[0] = player.getDuration();
219+
elapsedTime[0] = player.getElapsedTime();
220+
221+
if (!duration[0].equals("")) {
222+
getTransport().getPositionInfo().setTrackDuration(duration[0]);
223+
getTransport().getPositionInfo().setRelTime(elapsedTime[0]);
224+
YaaccLogger.d(getClass().getName(), "doSetTrackInfo: " + getTransport() + "Posinfo:" + getTransport().getPositionInfo() + " RelTime: " + getTransport().getPositionInfo().getRelTime());
225+
}
226+
});
218227
break;
219228
}
220229
}
221-
222230
}
223231

224232
private void updateTime() {

yaacc/src/main/java/de/yaacc/upnp/server/avtransport/AvTransportMediaRendererStopped.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,10 @@ public class AvTransportMediaRendererStopped extends Stopped<AvTransport> implem
4545
* Constructor.
4646
*
4747
* @param transport the state holder
48-
* @param upnpClient the upnpclient to use
4948
*/
50-
public AvTransportMediaRendererStopped(AvTransport transport,
51-
UpnpClient upnpClient) {
49+
public AvTransportMediaRendererStopped(AvTransport transport) {
5250
super(transport);
53-
this.upnpClient = upnpClient;
51+
this.upnpClient = AvTransport.getUpnpClient();
5452
}
5553

5654
/*

0 commit comments

Comments
 (0)