Question

I'm working on an android UPnP/DLNA app. I have a control point working where I can stream files from media server to renderer. I can pause/play and stop the file during playback but I cannot seem to figure out how to integrate a seekbar into the control point to show the progress of the playing file and be able to interact with the seekbar. I am using the Cling Java library to create the app. If anyone has any examples that could help me I would really appreciate it.

Thanks

I've tried to implement the SubscriptionCallback example and subscribe to LastChange

SubscriptionCallback callback = new SubscriptionCallback(service, 600) { // Timeout in seconds

                 public void established(GENASubscription sub) {
                     System.out.println("Established: " + sub.getSubscriptionId());


                 }
                 @Override
                 public void failed(GENASubscription sub, UpnpResponse response, Exception ex) {
                     System.err.println(
                         createDefaultFailureMessage(response, ex)
                     );
                 }
                 @Override
                 public void ended(GENASubscription sub, CancelReason reason, UpnpResponse response) {
                     // Reason should be null, or it didn't end regularly
                 }

                 public void eventReceived(GENASubscription sub) {
                     System.out.println("Event: " + sub.getCurrentSequence().getValue());


                               try {
                                   lastChange = new LastChange(
                                           new AVTransportLastChangeParser(),
                                           sub.getCurrentValues().get("LastChange").toString()
                                   );


                               } catch (Exception ex) {
                                   log.warning("Error parsing LastChange event content: " + ex);
                                   return;
                               }

                     Map<String, StateVariableValue> values = sub.getCurrentValues();
                     StateVariableValue status = values.get("Status");
                     System.out.println("Status is: " + status.toString());
                 }

                 public void eventsMissed(GENASubscription sub, int numberOfMissedEvents) {
                     System.out.println("Missed events: " + numberOfMissedEvents);
                 }
                @Override
                protected void failed(GENASubscription arg0,
                        UpnpResponse arg1, Exception arg2, String arg3) {

                }
            };

            upnpService.getControlPoint().execute(callback);

Then I try to get the duration of the current playing track:

System.out.println("Duration: "+lastChange.getEventedValue(0, AVTransportVariable.CurrentTrackDuration.class).getValue());

but this returns a NullPointerException.

Any ideas???????

************UPDATE***********

I have been trying to implement Seek() but have not had success.

I have my seekbar and listener but it it keeps failing when I drag the seekbar to a new position.

seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() 
{
        @Override
        public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) 
        {
            Log.i("SEEKTIME", "time:" + arg1);
            upnpService.getControlPoint().execute(new Seek(service, SeekMode.REL_TIME, arg0.toString())
            {
                @Override
                public void success(ActionInvocation invocation)
                {
                    //super.success(invocation);
                    Log.i("SEEKSUCCESS", "success seek");
                }
                @Override
                public void failure(ActionInvocation arg0, UpnpResponse arg1, String arg2)
                {
                    Log.i("SEEKFAIL", "fail seek");
                }
            });
        }

Any suggestions why this would be failing

Was it helpful?

Solution

You must poll the renderer for this kind of information (see AVTransport spec chapter 2.3.1). The spec encourages polling every second, but you can easily jam up a real hardware renderer (for which DLNA is still rather a fashionable pain in the a** than a vital part of the design). Our established practice is to send GetPositionInfo() request every 2-3 seconds and treat the returned RelativeTimePosition value only as an adjustment to locally running timer. For the seekbar sizing you also need the total length of current media. Ideally the renderer will tell you automatically when you subscribe to AVTransport.LastChange. I don't know Cling specifically but a quick look shows promising example in controlpoint.SubscriptionCallback. Unfortunately with real devices, LastChange often doesn't tell you anything much. Either the values are not there at all or have a constant inert value. So you will need to poll the GetMediaInfo() again and use MediaDuration value.

As for interaction, Seek() is your friend, ideally with parameters of Unit = REL_TIME and Target = your desired time offset. Be aware that a real world renderer may not be supporting this unit (mode) of seeking. Perhaps it supports only TRACK_NR in which case the seekbar is essentialy read-only for you. Again Cling should be able to tell you allowed values of A_ARG_TYPE_SeekMode for the particular renderer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top