/* * FireTVDiscoveryProvider * Connect SDK * * Copyright (c) 2015 LG Electronics. * Created by Oleksii Frolov on 08 Jul 2015 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.connectsdk.discovery.provider; import android.content.Context; import com.amazon.whisperplay.fling.media.controller.DiscoveryController; import com.amazon.whisperplay.fling.media.controller.RemoteMediaPlayer; import com.connectsdk.core.Util; import com.connectsdk.discovery.DiscoveryFilter; import com.connectsdk.discovery.DiscoveryProvider; import com.connectsdk.discovery.DiscoveryProviderListener; import com.connectsdk.service.FireTVService; import com.connectsdk.service.command.ServiceCommandError; import com.connectsdk.service.config.ServiceDescription; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; /** * FireTVDiscoveryProvider provides discovery implementation for FireTV devices. * FireTVDiscoveryProvider acts as a layer on top of Fling SDK, and requires the Fling SDK library * to function. This implementation does not use discovery filters because only one type of service * can be discovered. Currently it can discover only FireTV device with default media player * application. * * Using Connect SDK for discovery/control of FireTV devices will result in your app complying with * the Fling SDK terms of service. */ public class FireTVDiscoveryProvider implements DiscoveryProvider { private DiscoveryController discoveryController; private boolean isRunning; DiscoveryController.IDiscoveryListener fireTVListener; ConcurrentHashMap<String, ServiceDescription> foundServices = new ConcurrentHashMap<>(); CopyOnWriteArrayList<DiscoveryProviderListener> serviceListeners = new CopyOnWriteArrayList<>(); public FireTVDiscoveryProvider(Context context) { this(new DiscoveryController(context)); } public FireTVDiscoveryProvider(DiscoveryController discoveryController) { this.discoveryController = discoveryController; this.fireTVListener = new FireTVDiscoveryListener(); } /** * Safely start discovery. Ignore if it's already started. */ @Override public void start() { if (!isRunning) { discoveryController.start(fireTVListener); isRunning = true; } } /** * Safely stop discovery and remove all found FireTV services because they don't work when * discovery is stopped. Ignore if it's already stopped. */ @Override public void stop() { if (isRunning) { discoveryController.stop(); isRunning = false; } for (ServiceDescription serviceDescription : foundServices.values()) { notifyListenersThatServiceLost(serviceDescription); } foundServices.clear(); } /** * Safely restart discovery */ @Override public void restart() { stop(); start(); } /** * Invokes restart method since FlingSDK doesn't have analog of rescan */ @Override public void rescan() { // discovery controller doesn't have rescan capability restart(); } /** * Stop discovery and removes all cached services */ @Override public void reset() { foundServices.clear(); stop(); } @Override public void addListener(DiscoveryProviderListener listener) { serviceListeners.add(listener); } @Override public void removeListener(DiscoveryProviderListener listener) { serviceListeners.remove(listener); } /** * DiscoveryFilter is not used in current implementation */ @Override public void addDeviceFilter(DiscoveryFilter filter) { // intentionally left blank } /** * DiscoveryFilter is not used in current implementation */ @Override public void removeDeviceFilter(DiscoveryFilter filter) { // intentionally left blank } /** * DiscoveryFilter is not used in current implementation */ @Override public void setFilters(List<DiscoveryFilter> filters) { // intentionally left blank } @Override public boolean isEmpty() { return foundServices.isEmpty(); } private void notifyListenersThatServiceAdded(final ServiceDescription serviceDescription) { Util.runOnUI(new Runnable() { @Override public void run() { for (DiscoveryProviderListener listener : serviceListeners) { listener.onServiceAdded(FireTVDiscoveryProvider.this, serviceDescription); } } }); } private void notifyListenersThatServiceLost(final ServiceDescription serviceDescription) { Util.runOnUI(new Runnable() { @Override public void run() { for (DiscoveryProviderListener listener : serviceListeners) { listener.onServiceRemoved(FireTVDiscoveryProvider.this, serviceDescription); } } }); } private void notifyListenersThatDiscoveryFailed(final ServiceCommandError error) { Util.runOnUI(new Runnable() { @Override public void run() { for (DiscoveryProviderListener listener : serviceListeners) { listener.onServiceDiscoveryFailed(FireTVDiscoveryProvider.this, error); } } }); } class FireTVDiscoveryListener implements DiscoveryController.IDiscoveryListener { @Override public void playerDiscovered(RemoteMediaPlayer remoteMediaPlayer) { if (remoteMediaPlayer == null) { return; } String uid = remoteMediaPlayer.getUniqueIdentifier(); ServiceDescription serviceDescription = foundServices.get(uid); if (serviceDescription == null) { serviceDescription = new ServiceDescription(); updateServiceDescription(serviceDescription, remoteMediaPlayer); foundServices.put(uid, serviceDescription); notifyListenersThatServiceAdded(serviceDescription); } else { updateServiceDescription(serviceDescription, remoteMediaPlayer); } } @Override public void playerLost(RemoteMediaPlayer remoteMediaPlayer) { if (remoteMediaPlayer == null) { return; } ServiceDescription serviceDescription = foundServices.get(remoteMediaPlayer.getUniqueIdentifier()); if (serviceDescription != null) { notifyListenersThatServiceLost(serviceDescription); foundServices.remove(remoteMediaPlayer.getUniqueIdentifier()); } } @Override public void discoveryFailure() { final ServiceCommandError error = new ServiceCommandError("FireTV discovery failure"); notifyListenersThatDiscoveryFailed(error); } private void updateServiceDescription(ServiceDescription serviceDescription, RemoteMediaPlayer remoteMediaPlayer) { String uid = remoteMediaPlayer.getUniqueIdentifier(); serviceDescription.setDevice(remoteMediaPlayer); serviceDescription.setFriendlyName(remoteMediaPlayer.getName()); serviceDescription.setIpAddress(uid); serviceDescription.setServiceID(FireTVService.ID); serviceDescription.setUUID(uid); } } }