Android Open Source - controldlna Remote Play Service






From Project

Back to project page controldlna.

License

The source code is released under:

Copyright (c) 2013, Felix Ableitner All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:...

If you think the Android project controldlna listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
Copyright (c) 2013, Felix Ableitner/*from   w  w w . ja va  2  s  . com*/
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in the
    documentation and/or other materials provided with the distribution.
 * Neither the name of the <organization> nor the
    names of its contributors may be used to endorse or promote products
    derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.github.nutomic.controldlna.upnp;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

import com.github.nutomic.controldlna.R;

import org.teleal.cling.android.AndroidUpnpService;
import org.teleal.cling.android.AndroidUpnpServiceImpl;
import org.teleal.cling.model.action.ActionInvocation;
import org.teleal.cling.model.message.UpnpResponse;
import org.teleal.cling.model.meta.Device;
import org.teleal.cling.model.meta.LocalDevice;
import org.teleal.cling.model.meta.RemoteDevice;
import org.teleal.cling.model.meta.StateVariableAllowedValueRange;
import org.teleal.cling.model.types.ServiceType;
import org.teleal.cling.model.types.UDN;
import org.teleal.cling.registry.Registry;
import org.teleal.cling.registry.RegistryListener;
import org.teleal.cling.support.renderingcontrol.callback.GetVolume;

import java.util.Map.Entry;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Allows UPNP playback from different apps by providing a proxy interface.
 * You can communicate to this service via RemotePlayServiceBinder.
 *
 * @author Felix Ableitner
 *
 */
public class RemotePlayService extends Service implements RegistryListener {

  private static final String TAG = "RemotePlayService";

  protected Messenger mListener;

  protected ConcurrentHashMap<String, Device<?, ?, ?>> mDevices =
      new ConcurrentHashMap<String, Device<?, ?, ?>>();

  protected AndroidUpnpService mUpnpService;

  private ServiceConnection mUpnpServiceConnection = new ServiceConnection() {

    /**
     * Registers DeviceListener, adds known devices and starts search if requested.
     */
    public void onServiceConnected(ComponentName className, IBinder service) {
      mUpnpService = (AndroidUpnpService) service;
      mUpnpService.getRegistry().addListener(RemotePlayService.this);
      for (Device<?, ?, ?> d : mUpnpService.getControlPoint().getRegistry().getDevices()) {
        if (d instanceof LocalDevice) {
          localDeviceAdded(mUpnpService.getRegistry(), (LocalDevice) d);
        }
        else {
          remoteDeviceAdded(mUpnpService.getRegistry(), (RemoteDevice) d);
        }
      }
      mUpnpService.getControlPoint().search();
    }

    public void onServiceDisconnected(ComponentName className) {
      mUpnpService = null;
    }
  };

  /**
   * All active binders. The Hashmap value is unused.
   */
  WeakHashMap<RemotePlayServiceBinder, Boolean> mBinders =
      new WeakHashMap<RemotePlayServiceBinder, Boolean>();

  @Override
  public IBinder onBind(Intent itnent) {
    RemotePlayServiceBinder b = new RemotePlayServiceBinder(this);
    mBinders.put(b, true);
    return b;
  }

  /**
   * Binds to cling service, registers wifi state change listener.
   */
  @Override
  public void onCreate() {
    super.onCreate();
    bindService(new Intent(this, AndroidUpnpServiceImpl.class),
        mUpnpServiceConnection,  Context.BIND_AUTO_CREATE);

    IntentFilter filter = new IntentFilter();
    filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
    filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
    registerReceiver(mWifiReceiver, filter);
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
    unbindService(mUpnpServiceConnection);
    unregisterReceiver(mWifiReceiver);
  }

  /**
   * Sends msg via Messenger to Provider.
   */
  void sendMessage(Message msg) {
    if (mListener == null) {
      Log.w(TAG, "Listener is not initialized on send");
    }

    try {
      mListener.send(msg);
    }
    catch (RemoteException e) {
      Log.w(TAG, "Failed to send message", e);
    }
  }

  /**
   * Sends the error as a message via Messenger.
   * @param error
   */
  void sendError(String error) {
    Message msg = Message.obtain(null, Provider.MSG_ERROR, 0, 0);
    msg.getData().putString("error", error);
    sendMessage(msg);
  }

  /**
   * Starts device search on wifi connect, removes unreachable
   * devices on wifi disconnect.
   */
  private BroadcastReceiver mWifiReceiver = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
      ConnectivityManager connManager = (ConnectivityManager)
          getSystemService(CONNECTIVITY_SERVICE);
      NetworkInfo wifi = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);

      if (wifi.isConnected()) {
        if (mUpnpService != null) {
          for (Device<?, ?, ?> d :
              mUpnpService.getControlPoint().getRegistry().getDevices()) {
            deviceAdded(d);
          }
          mUpnpService.getControlPoint().search();
        }
      }
      else {
        for (Entry<String, Device<?, ?, ?>> d : mDevices.entrySet()) {
          if (mUpnpService.getControlPoint().getRegistry()
              .getDevice(new UDN(d.getKey()), false) == null) {
            deviceRemoved(d.getValue());
            for (RemotePlayServiceBinder b : mBinders.keySet()) {
              if (b.mCurrentRenderer != null &&
                  b.mCurrentRenderer.equals(d.getValue())) {
                b.mSubscriptionCallback.end();
                b.mCurrentRenderer = null;
              }
            }
          }
        }
      }
    }
  };

  /**
   * Returns a device service by name for direct queries.
   */
  org.teleal.cling.model.meta.Service<?, ?> getService(
      Device<?, ?, ?> device, String name) {
    return device.findService(new ServiceType("schemas-upnp-org", name));
  }

  /**
   * Gather device data and send it to Provider.
   */
  private void deviceAdded(final Device<?, ?, ?> device) {
    if (mDevices.containsValue(device))
      return;

    final org.teleal.cling.model.meta.Service<?, ?> rc = getService(device, "RenderingControl");
    if (rc == null || mListener == null)
      return;

    if (device.getType().getType().equals("MediaRenderer") &&
        device instanceof RemoteDevice) {
      mDevices.put(device.getIdentity().getUdn().toString(), device);

      try {
        mUpnpService.getControlPoint().execute(new GetVolume(rc) {

          @SuppressWarnings("rawtypes")
          @Override
          public void failure(ActionInvocation invocation,
              UpnpResponse operation, String defaultMessage) {
            Log.w(TAG, "Failed to get current Volume: " + defaultMessage);
            sendError("Failed to get current Volume: " + defaultMessage);
          }

          @SuppressWarnings("rawtypes")
          @Override
          public void received(ActionInvocation invocation, int currentVolume) {
            int maxVolume = 100;
            if (rc.getStateVariable("Volume") != null) {
              StateVariableAllowedValueRange volumeRange =
                  rc.getStateVariable("Volume")
                      .getTypeDetails().getAllowedValueRange();
              maxVolume = (int) volumeRange.getMaximum();
            }

            Message msg = Message.obtain(null, Provider.MSG_RENDERER_ADDED, 0, 0);

            String routeName = device.getDetails().getFriendlyName();
            if (getPackageName().endsWith(".debug")) {
              routeName = routeName + " (" + getString(R.string.debug) + ")";
            }
            msg.getData().putParcelable("device", new Provider.Device(
                device.getIdentity().getUdn().toString(),
                routeName,
                device.getDisplayString(),
                currentVolume,
                maxVolume));
            sendMessage(msg);
          }
        });
      }
      catch (IllegalArgumentException e) {
        e.printStackTrace();
        return;
      }
    }
  }

  /**
   * Remove the device from Provider.
   */
  private void deviceRemoved(Device<?, ?, ?> device) {
    if (device.getType().getType().equals("MediaRenderer") &&
        device instanceof RemoteDevice) {
      Message msg = Message.obtain(null, Provider.MSG_RENDERER_REMOVED, 0, 0);

      String udn = device.getIdentity().getUdn().toString();
      msg.getData().putString("id", udn);
      mDevices.remove(udn);
      sendMessage(msg);
    }
  }

  /**
   * If a device was updated, we just add it again (devices are stored in
   * maps, so adding the same one again just overwrites the old one).
   */
  private void deviceUpdated(Device<?, ?, ?> device) {
    deviceAdded(device);
  }

  @Override
  public void afterShutdown() {
  }

  @Override
  public void beforeShutdown(Registry registry) {
  }

  @Override
  public void localDeviceAdded(Registry registry, LocalDevice device) {
    deviceAdded(device);
  }

  @Override
  public void localDeviceRemoved(Registry registry, LocalDevice device) {
    deviceRemoved(device);
  }

  @Override
  public void remoteDeviceAdded(Registry registry, RemoteDevice device) {
    deviceAdded(device);
  }

  @Override
  public void remoteDeviceDiscoveryFailed(Registry registry, RemoteDevice device,
      Exception exception) {
    Log.w(TAG, "Remote device discovery failed", exception);
  }

  @Override
  public void remoteDeviceDiscoveryStarted(Registry registry, RemoteDevice device) {
  }

  @Override
  public void remoteDeviceRemoved(Registry registry, RemoteDevice device) {
    deviceRemoved(device);
  }

  @Override
  public void remoteDeviceUpdated(Registry registry, RemoteDevice device) {
    deviceUpdated(device);
  }

}




Java Source Code List

com.github.nutomic.controldlna.gui.MainActivity.java
com.github.nutomic.controldlna.gui.PreferencesActivity.java
com.github.nutomic.controldlna.gui.RouteFragment.java
com.github.nutomic.controldlna.gui.ServerFragment.java
com.github.nutomic.controldlna.localroute.Controller.java
com.github.nutomic.controldlna.localroute.ProviderService.java
com.github.nutomic.controldlna.localroute.Provider.java
com.github.nutomic.controldlna.mediarouter.MediaRouterPlayServiceBinder.java
com.github.nutomic.controldlna.mediarouter.MediaRouterPlayService.java
com.github.nutomic.controldlna.upnp.ProviderService.java
com.github.nutomic.controldlna.upnp.Provider.java
com.github.nutomic.controldlna.upnp.RemotePlayServiceBinder.java
com.github.nutomic.controldlna.upnp.RemotePlayService.java
com.github.nutomic.controldlna.utility.DeviceArrayAdapter.java
com.github.nutomic.controldlna.utility.FileArrayAdapter.java
com.github.nutomic.controldlna.utility.LoadImageTask.java
com.github.nutomic.controldlna.utility.RemoteImageView.java
com.github.nutomic.controldlna.utility.RouteAdapter.java