diff --git a/.gitignore b/.gitignore
index d4c41dd..84effb2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,3 @@ bin-debug/
bin-release/
.settings/
.DS_Store
-/build/android/aircast-jar.jar
diff --git a/README.md b/README.md
index a35e4e1..4d74330 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,19 @@
AirCast: Chromecast ANE for Adobe AIR
=====================================
-A native extension for Adobe AIR that enables you to cast audio and video content to Chromecast devices from iOS apps, with Android (hopefully) coming soon.
+A native extension for Adobe AIR that enables you to cast audio and video content to Chromecast devices from iOS apps.
-Requires Adobe AIR 16+.
+Requires Adobe AIR 20+.
iOS
---
-Based on [Renaud Bardet's seemingly abandoned iOS-only ANE project](https://github.com/renaudbardet/ANE-chromecast), support for iOS is now largely complete, including:
+Based on [Renaud Bardet's abandoned ANE](https://github.com/renaudbardet/ANE-chromecast), this native extension supports all of the basic features and functionality required to connect your iOS apps to Chromecast devices, including:
-* Support for [default Chromecast receiver app](https://developers.google.com/cast/docs/receiver_apps#default), no registration required
-* Upgrade to the latest Google Cast SDK
-* Support for amd64 and Adobe AIR 16, required for submission to the App Store
-
-Android
--------
-
-The current Android implementation, based on based on [cordova-chromecast](https://github.com/videostream/cordova-chromecast), is (in theory at least) nearly complete, but there are a few (hopefully minor) dependency issues to be resolved.
-
-Can you help?
+* Detects Chromecast devices on the network
+* Launch receiver applications
+* Control media playback and volume
+* Send and receive custom messages
+* Support for [default Chromecast receiver app](https://developers.google.com/cast/docs/receiver_apps#default), so no registration required
+* Uses the latest Google Cast SDK
+* Supports amd64 and the latest Adobe AIR SDK, required for submission to the App Store
diff --git a/android/.classpath b/android/.classpath
deleted file mode 100644
index 0ac43ec..0000000
--- a/android/.classpath
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/android/.gitignore b/android/.gitignore
deleted file mode 100644
index a22392a..0000000
--- a/android/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/bin
-/gen
diff --git a/android/.project b/android/.project
deleted file mode 100644
index f4cee00..0000000
--- a/android/.project
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
- aircast-jar
-
-
-
-
-
- com.android.ide.eclipse.adt.ResourceManagerBuilder
-
-
-
-
- com.android.ide.eclipse.adt.PreCompilerBuilder
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- com.android.ide.eclipse.adt.ApkBuilder
-
-
-
-
-
- com.android.ide.eclipse.adt.AndroidNature
- org.eclipse.jdt.core.javanature
-
-
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
deleted file mode 100644
index b11c57c..0000000
--- a/android/AndroidManifest.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
diff --git a/android/gen/com/mesmotronic/ane/aircast/BuildConfig.java b/android/gen/com/mesmotronic/ane/aircast/BuildConfig.java
deleted file mode 100644
index e388a86..0000000
--- a/android/gen/com/mesmotronic/ane/aircast/BuildConfig.java
+++ /dev/null
@@ -1,6 +0,0 @@
-/** Automatically generated file. DO NOT MODIFY */
-package com.mesmotronic.ane.aircast;
-
-public final class BuildConfig {
- public final static boolean DEBUG = true;
-}
\ No newline at end of file
diff --git a/android/libs/FlashRuntimeExtensions.jar b/android/libs/FlashRuntimeExtensions.jar
deleted file mode 100644
index 9f73378..0000000
Binary files a/android/libs/FlashRuntimeExtensions.jar and /dev/null differ
diff --git a/android/libs/android-support-v4.jar b/android/libs/android-support-v4.jar
deleted file mode 100644
index 96644ed..0000000
Binary files a/android/libs/android-support-v4.jar and /dev/null differ
diff --git a/android/project.properties b/android/project.properties
deleted file mode 100644
index af8e7ef..0000000
--- a/android/project.properties
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-target=Google Inc.:Google APIs:23
-android.library=true
-android.library.reference.1=C:/Program Files (x86)/Android/android-sdk/extras/android/support/v7/mediarouter
-android.library.reference.2=C:/Program Files (x86)/Android/android-sdk/extras/google/google_play_services/libproject/google-play-services_lib
diff --git a/android/src/com/mesmotronic/ane/aircast/AirCastExtension.java b/android/src/com/mesmotronic/ane/aircast/AirCastExtension.java
deleted file mode 100644
index f8f1686..0000000
--- a/android/src/com/mesmotronic/ane/aircast/AirCastExtension.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.mesmotronic.ane.aircast;
-
-import com.adobe.fre.FREContext;
-import com.adobe.fre.FREExtension;
-
-public class AirCastExtension implements FREExtension
-{
- public static String TAG = "AirCast";
-
- private static AirCastExtensionContext context;
-
- @Override
- public FREContext createContext(String extId)
- {
- context = new AirCastExtensionContext();
- return context;
- }
-
- @Override
- public void dispose()
- {
- context = null;
- }
-
- @Override
- public void initialize()
- {
- // Nothing to do here
- }
-
-}
diff --git a/android/src/com/mesmotronic/ane/aircast/AirCastExtensionContext.java b/android/src/com/mesmotronic/ane/aircast/AirCastExtensionContext.java
deleted file mode 100644
index 2585aac..0000000
--- a/android/src/com/mesmotronic/ane/aircast/AirCastExtensionContext.java
+++ /dev/null
@@ -1,838 +0,0 @@
-package com.mesmotronic.ane.aircast;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.app.Activity;
-import android.content.SharedPreferences;
-import android.support.v7.media.MediaRouteSelector;
-import android.support.v7.media.MediaRouter;
-import android.support.v7.media.MediaRouter.RouteInfo;
-
-import com.adobe.fre.FREContext;
-import com.adobe.fre.FREFunction;
-import com.adobe.fre.FREObject;
-import com.adobe.fre.FREWrongThreadException;
-import com.google.android.gms.cast.CastMediaControlIntent;
-import com.google.android.gms.cast.MediaInfo;
-
-public class AirCastExtensionContext
- extends FREContext
- implements ChromecastOnMediaUpdatedListener, ChromecastOnSessionUpdatedListener
-{
- private static final String SETTINGS_NAME = "AirCastSettings";
-
- private static final String EVENT_DEVICE_LIST_CHANGED = "AirCast.deviceListChanged";
- private static final String EVENT_CONNECT_TO_DEVICE = "AirCast.didConnectToDevice";
- private static final String EVENT_DISCONNECTED = "AirCast.didDisconnect";
- private static final String EVENT_RECEIVED_MEDIA_STATE_CHANGE = "AirCast.didReceiveMediaStateChange";
- private static final String EVENT_RECEIVED_CUSTOM_EVENT = "AirCast.didReceiveCustomEvent";
- private static final String EVENT_LOGGING = "LOGGING";
-
- private MediaRouter mMediaRouter;
- private MediaRouteSelector mMediaRouteSelector;
- private volatile ChromecastMediaRouterCallback mMediaRouterCallback = new ChromecastMediaRouterCallback();
- private String appId;
-
- private boolean isScanning = false;
- private boolean autoConnect = false;
- private String lastSessionId = null;
- private String lastAppId = null;
-
- private SharedPreferences settings;
-
- private volatile ChromecastSession currentSession;
-
- public AirCastExtensionContext() {}
-
- /*
- * NATIVE EXTENSION API
- */
-
- /**
- * Initialize the ANE
- */
- public BaseFunction initNE = new BaseFunction()
- {
- @Override
- public FREObject call(final FREContext context, FREObject[] args)
- {
- final Activity activity = getActivity();
-
- settings = activity.getSharedPreferences(SETTINGS_NAME, 0);
- lastSessionId = settings.getString("lastSessionId", "");
- lastAppId = settings.getString("lastAppId", "");
-
- appId = getStringFromFREObject(args[0]);
-
- mMediaRouter = MediaRouter.getInstance(activity);
-
- mMediaRouteSelector = new MediaRouteSelector.Builder()
- .addControlCategory(CastMediaControlIntent.categoryForCast(appId))
- .build();
-
- log("Initialize AirCast with app ID "+appId);
-
- activity.runOnUiThread(new Runnable()
- {
- public void run()
- {
- mMediaRouter = MediaRouter.getInstance(activity.getApplicationContext());
- mMediaRouteSelector = new MediaRouteSelector.Builder()
- .addControlCategory(CastMediaControlIntent.categoryForCast(appId))
- .build();
-
- mMediaRouterCallback.registerCallbacks(AirCastExtensionContext.this);
- mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
-
- isScanning = true;
-
- emitAllRoutes();
- }
- });
-
- return null;
- }
- };
-
- /**
- * TODO Implement this!
- */
- public BaseFunction scan = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- if (!isScanning)
- {
- mMediaRouter.addCallback(mMediaRouteSelector, mMediaRouterCallback, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN);
- }
-
- isScanning = true;
-
- emitAllRoutes();
-
- return null;
- }
- };
-
- /**
- * TODO Implement this!
- */
- public BaseFunction stopScan = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- if (isScanning)
- {
- mMediaRouter.removeCallback(mMediaRouterCallback);
- }
-
- isScanning = false;
-
- return null;
- }
- };
-
- /**
- * Connect to a Chromecast device
- */
- public BaseFunction connectToDevice = new BaseFunction()
- {
- @Override
- public FREObject call(final FREContext context, FREObject[] args)
- {
- final String routeId = getStringFromFREObject(args[0]);
-
- if (currentSession != null)
- {
- // TODO Should we disconnect and create a new session?
-
- return null;
- }
-
- setLastSessionId("");
-
- final Activity activity = getActivity();
-
- activity.runOnUiThread(new Runnable()
- {
- public void run()
- {
- mMediaRouter = MediaRouter.getInstance(activity.getApplicationContext());
- final List routeList = mMediaRouter.getRoutes();
-
- for (RouteInfo route : routeList)
- {
- if (route.getId().equals(routeId))
- {
- createSession(route);
- return;
- }
- }
-
- // TODO Dispatch "No route found" error?
-
- }
- });
-
- return null;
- }
- };
-
- /**
- * Helper for the creating of a session! The user-selected RouteInfo needs to be passed to a new ChromecastSession
- * @param route
- * @param callbackContext
- */
- private void createSession(final RouteInfo route)
- {
- currentSession = new ChromecastSession(route, this, this, this);
-
- // Launch the app.
- currentSession.launch(appId, new ChromecastSessionCallback()
- {
- @Override
- void onSuccess(Object object)
- {
- ChromecastSession session = (ChromecastSession) object;
-
- if (object == null)
- {
- onError("unknown");
- }
- else if (session == currentSession)
- {
- setLastSessionId(currentSession.getSessionId());
- currentSession.createSessionObject();
-
- dispatchStatus(EVENT_CONNECT_TO_DEVICE, routeToJSON(route));
- }
- }
-
- @Override
- void onError(String reason)
- {
- if (reason != null)
- {
- // log("createSession onError " + reason);
- // TODO Somehow return error to AIR app
- }
- else
- {
- // TODO Somehow return unknown error to AIR app
- }
- }
-
- });
- }
-
- private void joinSession(RouteInfo routeInfo)
- {
- ChromecastSession sessionJoinAttempt = new ChromecastSession(routeInfo, this, this, this);
-
- sessionJoinAttempt.join(this.appId, this.lastSessionId, new ChromecastSessionCallback()
- {
- @Override
- void onSuccess(Object object)
- {
- if (currentSession == null)
- {
- try
- {
- currentSession = (ChromecastSession) object;
- setLastSessionId(currentSession.getSessionId());
-
- dispatchStateChange();
-
-// sendJavascript("chrome.cast._.sessionJoined(" + currentSession.createSessionObject().toString() + ");");
- }
- catch (Exception e)
- {
- log(e.getMessage());
- }
- }
- }
-
- @Override
- void onError(String reason)
- {
-// log("sessionJoinAttempt error " +reason);
- }
-
- });
- }
-
- /**
- * Disconnect from Chromecast device
- */
- public BaseFunction disconnectFromDevice = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- mMediaRouter.selectRoute(null);
- return null;
- }
- };
-
- /**
- * Load media on the connected Chromecast device
- */
- public BaseFunction loadMedia = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- if (currentSession != null)
- {
- // url, thumbnailURL, title, desc, mimeType, startTime, autoPlay;
-
- String contentId = getStringFromFREObject(args[0]);
- String contentType = getStringFromFREObject(args[4]);
- Long duration = MediaInfo.UNKNOWN_DURATION;
- String streamType = ""; // TODO Make this auto detect?
- Boolean autoPlay = getBooleanFromFREObject(args[6]);
- Double currentTime = getDoubleFromFREObject(args[5]);
-
- Map matadataMap = new HashMap();
- matadataMap.put("title", getStringFromFREObject(args[2]));
- matadataMap.put("subtitle", getStringFromFREObject(args[3]));
- matadataMap.put("thumbnail", getStringFromFREObject(args[1]));
-
- JSONObject metadata = new JSONObject(matadataMap);
-
- currentSession.loadMedia
- (
- contentId,
- contentType,
- duration,
- streamType,
- autoPlay,
- currentTime,
- metadata,
-
- new ChromecastSessionCallback()
- {
- @Override
- void onSuccess(Object obj)
- {
- if (obj == null)
- {
- onError("unknown");
- }
- else
- {
- dispatchStatus(EVENT_RECEIVED_MEDIA_STATE_CHANGE, (JSONObject)obj);
- }
- }
-
- @Override
- void onError(String reason)
- {
- // TODO Error event to AIR
- }
- }
- );
- }
- else
- {
- // TODO Error event to AIR; "session_error"
- }
-
- return null;
- }
- };
-
- /**
- * Are we currently connected to a Chromecast device?
- */
- public BaseFunction isConnected = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- try
- {
- return FREObject.newObject(currentSession != null);
- }
- catch (FREWrongThreadException e)
- {
- return null;
- }
- }
- };
-
- /**
- * TODO Implement this
- */
- public BaseFunction isPlayingMedia = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- return null;
- }
- };
-
- /**
- * Play on the current media in the current session
- */
- public BaseFunction playCast = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- if (currentSession != null)
- {
- currentSession.mediaPlay(stateChangeCallback);
- }
-
- return null;
- }
- };
-
- /**
- * Pause on the current media in the current session
- */
- public BaseFunction pauseCast = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- if (currentSession != null)
- {
- currentSession.mediaPause(stateChangeCallback);
- }
-
- return null;
- }
- };
-
- /**
- * TODO Implement this
- */
- public BaseFunction updateStatsFromDevice = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- dispatchStateChange();
- return null;
- }
- };
-
- /**
- * Seeks the current media in the current session
- */
- public BaseFunction seek = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- if (currentSession != null)
- {
- Double seekTime = getDoubleFromFREObject(args[0]);
- String resumeState = "";
-
- currentSession.mediaSeek(seekTime.longValue() * 1000, resumeState, stateChangeCallback);
- }
-
- return null;
- }
- };
-
- /**
- * Stop the currently playing media
- */
- public BaseFunction stopCast = new BaseFunction()
- {
- @Override public FREObject call(FREContext context, FREObject[] args)
- {
- if (currentSession != null)
- {
- currentSession.mediaStop(stateChangeCallback);
- }
-
- return null;
- }
- };
-
- /**
- * Set volume on device
- */
- public BaseFunction setVolume = new BaseFunction()
- {
- @Override public FREObject call(FREContext context, FREObject[] args)
- {
- if (currentSession != null)
- {
- currentSession.setVolume(getDoubleFromFREObject(args[0]), stateChangeCallback);
- }
-
- return null;
- }
- };
-
- /**
- * Mute the device
- */
- public BaseFunction setMuted = new BaseFunction()
- {
- @Override public FREObject call(FREContext context, FREObject[] args)
- {
- if (currentSession != null)
- {
- Boolean muted = getBooleanFromFREObject(args[0]);
- currentSession.mediaSetMuted(muted, stateChangeCallback);
- }
-
- return null;
- }
- };
-
- /**
- * Send a custom event to the device
- */
- public BaseFunction sendCustomEvent = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- String namespace = getStringFromFREObject(args[0]);
- String message = getStringFromFREObject(args[1]);
-
- if (currentSession != null)
- {
- currentSession.sendMessage(namespace, message, new ChromecastSessionCallback()
- {
- @Override
- void onSuccess(Object obj)
- {
- dispatchStatus(EVENT_RECEIVED_CUSTOM_EVENT, (JSONObject) obj);
- }
-
- @Override
- void onError(String reason)
- {
- // TODO Error event in AIR
- }
- });
- }
-
- return null;
- }
- };
-
- /**
- * Adds a listener to a specific namespace
- */
- public BaseFunction addMessageListener = new BaseFunction()
- {
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- String namespace = getStringFromFREObject(args[0]);
-
- if (currentSession != null)
- {
- currentSession.addMessageListener(namespace);
- }
-
- return null;
- }
- };
-
- /*
- * INTERNAL FUNCTIONS
- */
-
- private void setLastSessionId(String sessionId)
- {
- this.lastSessionId = sessionId;
- this.settings.edit().putString("lastSessionId", sessionId).apply();
- }
-
- @Override
- public void dispose()
- {
- mMediaRouter.removeCallback(mMediaRouterCallback);
- }
-
- /**
- * Stops the session
- * @param callbackContext
- * @return
- */
- public boolean sessionStop()
- {
- if (currentSession != null)
- {
- currentSession.kill(stateChangeCallback);
- currentSession = null;
- setLastSessionId("");
- }
-
- return true;
- }
-
- /**
- * Stops the session
- * @param callbackContext
- * @return
- */
- public boolean sessionLeave()
- {
- if (this.currentSession != null)
- {
- this.currentSession.leave(stateChangeCallback);
- this.currentSession = null;
- this.setLastSessionId("");
- }
-
- return true;
- }
-
- public void emitAllRoutes()
- {
- final Activity activity = getActivity();
-
- activity.runOnUiThread(new Runnable()
- {
- public void run()
- {
- mMediaRouter = MediaRouter.getInstance(activity.getApplicationContext());
- List routeList = mMediaRouter.getRoutes();
-
- JSONArray devices = new JSONArray();
-
- for (RouteInfo route : routeList)
- {
- if (!route.getName().equals("Phone") && route.getId().indexOf("Cast") > -1)
- {
- devices.put(routeToJSON(route));
- }
- }
-
- dispatchStatus(EVENT_DEVICE_LIST_CHANGED, devices);
- }
- });
- }
-
- /**
- * Called when a route is discovered
- * @param router
- * @param route
- */
- protected void onRouteAdded(MediaRouter router, final RouteInfo route, FREContext context)
- {
-// if (this.autoConnect && this.currentSession == null && !route.getName().equals("Phone"))
-// {
-// log("Attempting to join route " + route.getName());
-// this.joinSession(route, context);
-// }
-// else
-// {
-// log("For some reason, not attempting to join route " + route.getName() + ", " + this.currentSession + ", " + this.autoConnect);
-// }
-//
-// if (!route.getName().equals("Phone") && route.getId().indexOf("Cast") > -1)
-// {
-// sendJavascript("chrome.cast._.routeAdded(" + routeToJSON(route) + ")");
-// }
-
- emitAllRoutes();
- }
-
- /**
- * Called when a discovered route is lost
- * @param router
- * @param route
- */
- protected void onRouteRemoved(MediaRouter router, RouteInfo route)
- {
- emitAllRoutes();
- }
-
- /**
- * Called when a route is selected through the MediaRouter
- *
- * @param router
- * @param route
- */
- protected void onRouteSelected(MediaRouter router, RouteInfo route)
- {
- createSession(route);
- }
-
- /**
- * Called when a route is unselected through the MediaRouter
- *
- * @param router
- * @param route
- */
- protected void onRouteUnselected(MediaRouter router, RouteInfo route)
- {
- dispatchStatus(EVENT_DISCONNECTED, routeToJSON(route));
- }
-
- /**
- * Converts RouteInfo data into a format consistent with the iOS elements
- * of the ANE ready to be returned to AIR
- *
- * @param route
- * @return
- */
- private JSONObject routeToJSON(RouteInfo route)
- {
- JSONObject obj = new JSONObject();
-
- try
- {
- obj.put("ipAddress", "");
- obj.put("servicePort", "");
- obj.put("deviceID", route.getId());
- obj.put("friendlyName", route.getName());
- obj.put("manufacturer", "");
- obj.put("modelName", "");
- obj.put("icons", new JSONArray());
- }
- catch (JSONException e)
- {
- e.printStackTrace();
- }
-
- return obj;
- }
-
- @Override
- public void onMediaUpdated(boolean isAlive, JSONObject media)
- {
- dispatchStateChange();
-
-// if (isAlive)
-// {
-// sendJavascript("chrome.cast._.mediaUpdated(true, " + media.toString() +");");
-// }
-// else
-// {
-// sendJavascript("chrome.cast._.mediaUpdated(false, " + media.toString() +");");
-// }
- }
-
- @Override
- public void onSessionUpdated(boolean isAlive, JSONObject session)
- {
- if (isAlive)
- {
- dispatchStateChange();
-// sendJavascript("chrome.cast._.sessionUpdated(true, " + session.toString() + ");");
- }
- else
- {
-// sendJavascript("chrome.cast._.sessionUpdated(false, " + session.toString() + ");");
- this.currentSession = null;
- }
- }
-
- @Override
- public void onMediaLoaded(JSONObject media)
- {
- dispatchStateChange();
-// sendJavascript("chrome.cast._.mediaLoaded(true, " + media.toString() +");");
- }
-
- @Override
- public void onMessage(ChromecastSession session, String namespace, String message)
- {
- dispatchStateChange();
-// sendJavascript("chrome.cast._.onMessage('" + session.getSessionId() +"', '" + namespace + "', '" + message + "')");
- }
-
- /**
- * Default callback for any action that results in the media state changing
- *
- * TODO Implement this
- */
- private ChromecastSessionCallback stateChangeCallback = new ChromecastSessionCallback()
- {
- @Override
- void onSuccess(Object object)
- {
- dispatchStateChange();
- }
-
- @Override
- void onError(String reason)
- {
- // TODO Dispatch errors back to AIR?
- }
- };
-
- /**
- * Dispatches the current media state back to AIR
- */
- private void dispatchStateChange()
- {
- dispatchStatus(EVENT_RECEIVED_MEDIA_STATE_CHANGE, currentSession.createSessionObject());
- }
-
- /**
- * Dispatch a status event to AIR
- *
- * @param context
- * @param level
- * @param code
- */
- private void dispatchStatus(String type, String data)
- {
- dispatchStatusEventAsync(type, data);
- }
-
- private void dispatchStatus(String type, JSONObject data)
- {
- dispatchStatus(type, data.toString());
- }
-
- private void dispatchStatus(String type, JSONArray data)
- {
- dispatchStatus(type, data.toString());
- }
-
- private void log(String s)
- {
- dispatchStatus(EVENT_LOGGING, s);
- }
-
- @Override
- public Map getFunctions()
- {
- Map functions = new HashMap();
-
- functions.put("initNE", initNE);
- functions.put("scan", scan);
- functions.put("stopScan", stopScan);
- functions.put("connectToDevice", connectToDevice);
- functions.put("disconnectFromDevice", disconnectFromDevice);
- functions.put("loadMedia", loadMedia);
- functions.put("isConnected", isConnected);
- functions.put("isPlayingMedia", isPlayingMedia);
- functions.put("playCast", playCast);
- functions.put("pauseCast", pauseCast);
- functions.put("updateStatsFromDevice", updateStatsFromDevice);
- functions.put("seek", seek);
- functions.put("stopCast", stopCast);
- functions.put("setVolume", setVolume);
- functions.put("setMuted", setMuted);
- functions.put("sendCustomEvent", sendCustomEvent);
-
- return functions;
- }
-
-}
diff --git a/android/src/com/mesmotronic/ane/aircast/BaseFunction.java b/android/src/com/mesmotronic/ane/aircast/BaseFunction.java
deleted file mode 100644
index 189b06b..0000000
--- a/android/src/com/mesmotronic/ane/aircast/BaseFunction.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package com.mesmotronic.ane.aircast;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.os.Bundle;
-
-import com.adobe.fre.FREArray;
-import com.adobe.fre.FREContext;
-import com.adobe.fre.FREFunction;
-import com.adobe.fre.FREObject;
-
-public class BaseFunction implements FREFunction
-{
- @Override
- public FREObject call(FREContext context, FREObject[] args)
- {
- return null;
- }
-
- protected String getStringFromFREObject(FREObject object)
- {
- try
- {
- return object.getAsString();
- }
- catch (Exception e)
- {
- e.printStackTrace();
- return "";
- }
- }
-
- protected Boolean getBooleanFromFREObject(FREObject object)
- {
- try
- {
- return object.getAsBool();
- }
- catch(Exception e)
- {
- e.printStackTrace();
- return false;
- }
- }
-
- protected Double getDoubleFromFREObject(FREObject object)
- {
- try
- {
- return object.getAsDouble();
- }
- catch(Exception e)
- {
- e.printStackTrace();
- return 0.0;
- }
- }
-
- protected List getListOfStringFromFREArray(FREArray array)
- {
- List result = new ArrayList();
-
- try
- {
- for (int i = 0; i < array.getLength(); i++)
- {
- try
- {
- result.add(getStringFromFREObject(array.getObjectAt((long)i)));
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
- }
- catch (Exception e)
- {
- e.printStackTrace();
- return null;
- }
-
- return result;
- }
-
- protected Bundle getBundleOfStringFromFREArrays(FREArray keys, FREArray values)
- {
- Bundle result = new Bundle();
-
- try
- {
- long length = Math.min(keys.getLength(), values.getLength());
- for (int i = 0; i < length; i++)
- {
- try
- {
- String key = getStringFromFREObject(keys.getObjectAt((long)i));
- String value = getStringFromFREObject(values.getObjectAt((long)i));
- result.putString(key, value);
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
- }
- catch (Exception e)
- {
- e.printStackTrace();
- return null;
- }
-
- return result;
- }
-}
diff --git a/android/src/com/mesmotronic/ane/aircast/ChromecastException.java b/android/src/com/mesmotronic/ane/aircast/ChromecastException.java
deleted file mode 100644
index 04b4edb..0000000
--- a/android/src/com/mesmotronic/ane/aircast/ChromecastException.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.mesmotronic.ane.aircast;
-
-public class ChromecastException extends Exception {
-
-}
diff --git a/android/src/com/mesmotronic/ane/aircast/ChromecastMediaController.java b/android/src/com/mesmotronic/ane/aircast/ChromecastMediaController.java
deleted file mode 100644
index 033c85e..0000000
--- a/android/src/com/mesmotronic/ane/aircast/ChromecastMediaController.java
+++ /dev/null
@@ -1,169 +0,0 @@
-package com.mesmotronic.ane.aircast;
-
-import com.google.android.gms.cast.MediaInfo;
-import com.google.android.gms.cast.MediaMetadata;
-import com.google.android.gms.cast.RemoteMediaPlayer;
-import com.google.android.gms.cast.RemoteMediaPlayer.MediaChannelResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.common.api.PendingResult;
-import com.google.android.gms.common.api.ResultCallback;
-import com.google.android.gms.common.images.WebImage;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.net.Uri;
-
-public class ChromecastMediaController
-{
- private RemoteMediaPlayer remote = null;
-
- public ChromecastMediaController(RemoteMediaPlayer mRemoteMediaPlayer)
- {
- remote = mRemoteMediaPlayer;
- }
-
- public MediaInfo createLoadUrlRequest(String contentId, String contentType, long duration, String streamType, JSONObject metadata)
- {
- // Try creating a GENERIC MediaMetadata obj
- MediaMetadata mediaMetadata = new MediaMetadata();
-
- try
- {
- int metadataType = metadata.has("metadataType")
- ? metadata.getInt("metadataType")
- : MediaMetadata.MEDIA_TYPE_MOVIE;
-
- // GENERIC
- if (metadataType == MediaMetadata.MEDIA_TYPE_GENERIC)
- {
- mediaMetadata = new MediaMetadata(); // Creates GENERIC MediaMetaData
- mediaMetadata.putString(MediaMetadata.KEY_TITLE, (metadata.has("title")) ? metadata.getString("title") : "");
- mediaMetadata.putString(MediaMetadata.KEY_SUBTITLE, (metadata.has("title")) ? metadata.getString("subtitle") : "");
- mediaMetadata = addImages(metadata, mediaMetadata);
- }
-
- }
- catch(Exception e)
- {
- e.printStackTrace();
- // Fallback
- mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
- }
-
- int _streamType = MediaInfo.STREAM_TYPE_BUFFERED;
-
- if (streamType.equals("live"))
- {
- _streamType = MediaInfo.STREAM_TYPE_LIVE;
- }
- else if (streamType.equals("other"))
- {
- _streamType = MediaInfo.STREAM_TYPE_NONE;
- }
-
- MediaInfo mediaInfo = new MediaInfo.Builder(contentId)
- .setContentType(contentType)
- .setStreamType(_streamType)
- .setStreamDuration(duration)
- .setMetadata(mediaMetadata)
- .build();
-
- return mediaInfo;
- }
-
- public void play(GoogleApiClient apiClient, ChromecastSessionCallback callback)
- {
- PendingResult res = this.remote.play(apiClient);
- res.setResultCallback(this.createMediaCallback(callback));
- }
-
- public void pause(GoogleApiClient apiClient, ChromecastSessionCallback callback)
- {
- PendingResult res = this.remote.pause(apiClient);
- res.setResultCallback(this.createMediaCallback(callback));
- }
-
- public void stop(GoogleApiClient apiClient, ChromecastSessionCallback callback)
- {
- PendingResult res = this.remote.stop(apiClient);
- res.setResultCallback(this.createMediaCallback(callback));
- }
-
- public void seek(long seekPosition, String resumeState, GoogleApiClient apiClient, ChromecastSessionCallback callback)
- {
- PendingResult res = null;
-
- if (resumeState != null && !resumeState.equals(""))
- {
- if (resumeState.equals("PLAYBACK_PAUSE"))
- {
- res = this.remote.seek(apiClient, seekPosition, RemoteMediaPlayer.RESUME_STATE_PAUSE);
- }
- else if (resumeState.equals("PLAYBACK_START"))
- {
- res = this.remote.seek(apiClient, seekPosition, RemoteMediaPlayer.RESUME_STATE_PLAY);
- }
- else
- {
- res = this.remote.seek(apiClient, seekPosition, RemoteMediaPlayer.RESUME_STATE_UNCHANGED);
- }
- }
-
- if (res == null)
- {
- res = this.remote.seek(apiClient, seekPosition);
- }
-
- res.setResultCallback(this.createMediaCallback(callback));
- }
-
- public void setVolume(double volume, GoogleApiClient apiClient, ChromecastSessionCallback callback)
- {
- PendingResult res = this.remote.setStreamVolume(apiClient, volume);
- res.setResultCallback(this.createMediaCallback(callback));
- }
-
- public void setMuted(boolean muted, GoogleApiClient apiClient, ChromecastSessionCallback callback)
- {
- PendingResult res = this.remote.setStreamMute(apiClient, muted);
- res.setResultCallback(this.createMediaCallback(callback));
- }
-
- private ResultCallback createMediaCallback(final ChromecastSessionCallback callback)
- {
- return new ResultCallback()
- {
- @Override
- public void onResult(MediaChannelResult result)
- {
- if (result.getStatus().isSuccess())
- {
- callback.onSuccess();
- }
- else
- {
- callback.onError("channel_error");
- }
- }
- };
- }
-
- private MediaMetadata addImages(JSONObject metadata, MediaMetadata mediaMetadata) throws JSONException
- {
- if (metadata.has("thumbnail"))
- {
- String imageUrl = metadata.getString("thumbnail");
-
- if (imageUrl.indexOf("http") == 0)
- {
- Uri imageURI = Uri.parse( imageUrl );
- WebImage webImage = new WebImage(imageURI);
- mediaMetadata.addImage(webImage);
- }
- }
-
- return mediaMetadata;
- }
-
-}
diff --git a/android/src/com/mesmotronic/ane/aircast/ChromecastMediaRouterCallback.java b/android/src/com/mesmotronic/ane/aircast/ChromecastMediaRouterCallback.java
deleted file mode 100644
index 17e9c63..0000000
--- a/android/src/com/mesmotronic/ane/aircast/ChromecastMediaRouterCallback.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.mesmotronic.ane.aircast;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-import android.support.v7.media.MediaRouter;
-import android.support.v7.media.MediaRouter.RouteInfo;
-
-public class ChromecastMediaRouterCallback extends MediaRouter.Callback {
- private volatile ArrayList routes = new ArrayList();
-
- private AirCastExtensionContext callback = null;
-
- public void registerCallbacks(AirCastExtensionContext instance)
- {
- callback = instance;
- }
-
- public synchronized RouteInfo getRoute(String id)
- {
- for (RouteInfo i : this.routes)
- {
- if (i.getId().equals(id))
- {
- return i;
- }
- }
- return null;
- }
-
- public synchronized RouteInfo getRoute(int index)
- {
- return routes.get(index);
- }
-
- public synchronized Collection getRoutes()
- {
- return routes;
- }
-
- @Override
- public synchronized void onRouteAdded(MediaRouter router, RouteInfo route)
- {
- routes.add(route);
-
- if (callback != null)
- {
- callback.onRouteAdded(router, route, null);
- }
- }
-
- @Override
- public void onRouteRemoved(MediaRouter router, RouteInfo route)
- {
- routes.remove(route);
-
- if (callback != null)
- {
- callback.onRouteRemoved(router, route);
- }
- }
-
- @Override
- public void onRouteSelected(MediaRouter router, RouteInfo info)
- {
- if (callback != null)
- {
- callback.onRouteSelected(router, info);
- }
- }
-
- @Override
- public void onRouteUnselected(MediaRouter router, RouteInfo info)
- {
- if (callback != null)
- {
- callback.onRouteUnselected(router, info);
- }
- }
-}
diff --git a/android/src/com/mesmotronic/ane/aircast/ChromecastOnMediaUpdatedListener.java b/android/src/com/mesmotronic/ane/aircast/ChromecastOnMediaUpdatedListener.java
deleted file mode 100644
index 945a745..0000000
--- a/android/src/com/mesmotronic/ane/aircast/ChromecastOnMediaUpdatedListener.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.mesmotronic.ane.aircast;
-
-import org.json.JSONObject;
-
-public interface ChromecastOnMediaUpdatedListener
-{
- void onMediaLoaded(JSONObject media);
- void onMediaUpdated(boolean isAlive, JSONObject media);
-}
\ No newline at end of file
diff --git a/android/src/com/mesmotronic/ane/aircast/ChromecastOnSessionUpdatedListener.java b/android/src/com/mesmotronic/ane/aircast/ChromecastOnSessionUpdatedListener.java
deleted file mode 100644
index bcfd7c5..0000000
--- a/android/src/com/mesmotronic/ane/aircast/ChromecastOnSessionUpdatedListener.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.mesmotronic.ane.aircast;
-
-import org.json.JSONObject;
-
-public interface ChromecastOnSessionUpdatedListener
-{
- void onSessionUpdated(boolean isAlive, JSONObject properties);
- void onMessage(ChromecastSession session, String namespace, String message);
-}
\ No newline at end of file
diff --git a/android/src/com/mesmotronic/ane/aircast/ChromecastSession.java b/android/src/com/mesmotronic/ane/aircast/ChromecastSession.java
deleted file mode 100644
index f9b29db..0000000
--- a/android/src/com/mesmotronic/ane/aircast/ChromecastSession.java
+++ /dev/null
@@ -1,790 +0,0 @@
-package com.mesmotronic.ane.aircast;
-
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.List;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import com.adobe.fre.FREContext;
-import com.google.android.gms.cast.ApplicationMetadata;
-import com.google.android.gms.cast.Cast;
-import com.google.android.gms.cast.Cast.ApplicationConnectionResult;
-import com.google.android.gms.cast.CastDevice;
-import com.google.android.gms.cast.MediaInfo;
-import com.google.android.gms.cast.MediaStatus;
-import com.google.android.gms.cast.RemoteMediaPlayer;
-import com.google.android.gms.cast.RemoteMediaPlayer.MediaChannelResult;
-import com.google.android.gms.cast.RemoteMediaPlayer.OnMetadataUpdatedListener;
-import com.google.android.gms.cast.RemoteMediaPlayer.OnStatusUpdatedListener;
-import com.google.android.gms.common.ConnectionResult;
-import com.google.android.gms.common.api.GoogleApiClient;
-import com.google.android.gms.common.api.ResultCallback;
-import com.google.android.gms.common.api.Status;
-import com.google.android.gms.common.images.WebImage;
-
-import android.os.Bundle;
-import android.support.v7.media.MediaRouter.RouteInfo;
-
-/*
- * All of the Chromecast session specific functions should start here.
- */
-public class ChromecastSession
- extends Cast.Listener
- implements
- GoogleApiClient.ConnectionCallbacks,
- GoogleApiClient.OnConnectionFailedListener,
- OnMetadataUpdatedListener,
- OnStatusUpdatedListener,
- Cast.MessageReceivedCallback {
-
- private RouteInfo routeInfo = null;
- private volatile GoogleApiClient mApiClient = null;
- private volatile RemoteMediaPlayer mRemoteMediaPlayer;
- private FREContext context = null;
- private CastDevice device = null;
- private ChromecastMediaController chromecastMediaController;
- private ChromecastOnMediaUpdatedListener onMediaUpdatedListener;
- private ChromecastOnSessionUpdatedListener onSessionUpdatedListener;
-
- private volatile String appId;
- private volatile String displayName;
- private volatile List appImages;
- private volatile String sessionId = null;
- private volatile String lastSessionId = null;
- private boolean isConnected = false;
-
- private ChromecastSessionCallback launchCallback;
- private ChromecastSessionCallback joinSessionCallback;
-
- private boolean joinInsteadOfConnecting = false;
- private HashSet messageNamespaces = new HashSet();
-
- public ChromecastSession(RouteInfo routeInfo, FREContext freContext,
- ChromecastOnMediaUpdatedListener onMediaUpdatedListener,
- ChromecastOnSessionUpdatedListener onSessionUpdatedListener
- )
- {
- this.context = freContext;
- this.onMediaUpdatedListener = onMediaUpdatedListener;
- this.onSessionUpdatedListener = onSessionUpdatedListener;
- this.routeInfo = routeInfo;
- this.device = CastDevice.getFromBundle(this.routeInfo.getExtras());
-
- this.mRemoteMediaPlayer = new RemoteMediaPlayer();
- this.mRemoteMediaPlayer.setOnMetadataUpdatedListener(this);
- this.mRemoteMediaPlayer.setOnStatusUpdatedListener(this);
-
- this.chromecastMediaController = new ChromecastMediaController(mRemoteMediaPlayer);
- }
-
-
- /**
- * Sets the wheels in motion - connects to the Chromecast and launches the given app
- * @param appId
- */
- public void launch(String appId, ChromecastSessionCallback launchCallback)
- {
- this.appId = appId;
- this.launchCallback = launchCallback;
- this.connectToDevice();
- }
-
- public boolean isConnected()
- {
- return this.isConnected;
- }
-
- /**
- * Adds a message listener if one does not already exist
- * @param namespace
- */
- public void addMessageListener(String namespace)
- {
- if (messageNamespaces.contains(namespace) == false)
- {
- try
- {
- Cast.CastApi.setMessageReceivedCallbacks(mApiClient, namespace, this);
- messageNamespaces.add(namespace);
- }
- catch(Exception e)
- {
- //
- }
- }
- }
-
- /**
- * Sends a message to a specified namespace
- * @param namespace
- * @param message
- * @param callback
- */
- public void sendMessage(String namespace, String message, final ChromecastSessionCallback callback)
- {
- try
- {
- Cast.CastApi.sendMessage(mApiClient, namespace, message).setResultCallback(new ResultCallback()
- {
- @Override
- public void onResult(Status result)
- {
- if (result.isSuccess())
- {
- callback.onSuccess();
- }
- else
- {
- callback.onError(result.toString());
- }
- }
- });
- }
- catch(Exception e)
- {
- callback.onError(e.getMessage());
- }
- }
-
- /**
- * Join a currently running app with an appId and a session
- * @param appId
- * @param sessionId
- * @param joinSessionCallback
- */
- public void join (String appId, String sessionId, ChromecastSessionCallback joinSessionCallback)
- {
- this.appId = appId;
- this.joinSessionCallback = joinSessionCallback;
- this.joinInsteadOfConnecting = true;
- this.lastSessionId = sessionId;
- this.connectToDevice();
- }
-
- /**
- * Kills a session and it's underlying media player
- * @param callback
- */
- public void kill (final ChromecastSessionCallback callback)
- {
- try
- {
- Cast.CastApi.stopApplication(mApiClient);
- mApiClient.disconnect();
- }
- catch(Exception e)
- {
- //
- }
-
- callback.onSuccess();
- }
-
- /**
- * Leaves the session.
- * @param callback
- */
- public void leave (final ChromecastSessionCallback callback)
- {
- try
- {
- Cast.CastApi.leaveApplication(mApiClient);
- }
- catch(Exception e)
- {
- //
- }
-
- callback.onSuccess();
- }
-
- /**
- * Loads media over the media API
- * @param contentId - The URL of the content
- * @param contentType - The MIME type of the content
- * @param duration - The length of the video (if known)
- * @param streamType
- * @param autoPlay - Whether or not to start the video playing or not
- * @param currentTime - Where in the video to begin playing from
- * @param callback
- * @return
- */
- public boolean loadMedia(String contentId, String contentType, long duration,
- String streamType, boolean autoPlay, double currentTime,
- JSONObject metadata, final ChromecastSessionCallback callback
- )
- {
- try
- {
- MediaInfo mediaInfo = chromecastMediaController.createLoadUrlRequest(contentId, contentType, duration, streamType, metadata);
-
- mRemoteMediaPlayer.load
- (
- mApiClient,
- mediaInfo,
- autoPlay,
- (long)(currentTime * 1000))
-
- .setResultCallback(new ResultCallback()
- {
- @Override
- public void onResult(MediaChannelResult result)
- {
- if (result.getStatus().isSuccess())
- {
- System.out.println("Media loaded successfully");
-
- ChromecastSession.this.onMediaUpdatedListener.onMediaLoaded(ChromecastSession.this.createMediaObject());
- callback.onSuccess(ChromecastSession.this.createMediaObject());
- }
- else
- {
- callback.onError("session_error");
- }
- }
- }
- );
- }
- catch (IllegalStateException e)
- {
- e.printStackTrace();
- System.out.println("Problem occurred with media during loading");
- callback.onError("session_error");
-
- return false;
- }
- catch (Exception e)
- {
- e.printStackTrace();
- callback.onError("session_error");
- System.out.println("Problem opening media during loading");
-
- return false;
- }
-
- return true;
- }
-
- /**
- * Media API - Calls play on the current media
- * @param callback
- */
- public void mediaPlay(ChromecastSessionCallback callback)
- {
- chromecastMediaController.play(mApiClient, callback);
- }
-
- /**
- * Media API - Calls pause on the current media
- * @param callback
- */
- public void mediaPause(ChromecastSessionCallback callback)
- {
- chromecastMediaController.pause(mApiClient, callback);
- }
-
- /**
- * Media API - Seeks the current playing media
- * @param seekPosition - Seconds to seek to
- * @param resumeState - Resume state once seeking is complete: PLAYBACK_PAUSE or PLAYBACK_START
- * @param callback
- */
- public void mediaSeek(long seekPosition, String resumeState, ChromecastSessionCallback callback)
- {
- chromecastMediaController.seek(seekPosition, resumeState, mApiClient, callback);
- }
-
- /**
- * Media API - Sets the volume on the current playing media object NOT ON THE CHROMECAST DIRECTLY
- * @param level
- * @param callback
- */
- public void mediaSetVolume(double level, ChromecastSessionCallback callback)
- {
- chromecastMediaController.setVolume(level, mApiClient, callback);
- }
-
- /**
- * Media API - Sets the muted state on the current playing media NOT THE CHROMECAST DIRECTLY
- * @param muted
- * @param callback
- */
- public void mediaSetMuted(boolean muted, ChromecastSessionCallback callback)
- {
- chromecastMediaController.setMuted(muted, mApiClient, callback);
- }
-
- /**
- * Media API - Stops and unloads the current playing media
- * @param callback
- */
- public void mediaStop(ChromecastSessionCallback callback)
- {
- chromecastMediaController.stop(mApiClient, callback);
- }
-
-
- /**
- * Sets the receiver volume level
- * @param volume
- * @param callback
- */
- public void setVolume(double volume, ChromecastSessionCallback callback)
- {
- try
- {
- Cast.CastApi.setVolume(mApiClient, volume);
- callback.onSuccess();
- }
- catch (Exception e)
- {
- e.printStackTrace();
- callback.onError(e.getMessage());
- }
- }
-
- /**
- * Mutes the receiver
- * @param muted
- * @param callback
- */
- public void setMute(boolean muted, ChromecastSessionCallback callback)
- {
- try
- {
- Cast.CastApi.setMute(mApiClient, muted);
- callback.onSuccess();
- }
- catch (Exception e)
- {
- e.printStackTrace();
- callback.onError(e.getMessage());
- }
- }
-
- /**
- * Connects to the device with all callbacks and things
- */
- private void connectToDevice()
- {
- try
- {
- Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions.builder(this.device, this);
-
- this.mApiClient = new GoogleApiClient.Builder(this.context.getActivity().getApplicationContext())
- .addApi(Cast.API, apiOptionsBuilder.build())
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .build();
-
- this.mApiClient.connect();
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- }
-
- /**
- * Launches the application and gets a new session
- */
- private void launchApplication()
- {
- Cast.CastApi.launchApplication(mApiClient, this.appId, false)
- .setResultCallback(launchApplicationResultCallback);
- }
-
- /**
- * Attemps to join an already running session
- */
- private void joinApplication()
- {
- Cast.CastApi.joinApplication(this.mApiClient, this.appId, this.lastSessionId)
- .setResultCallback(joinApplicationResultCallback);
- }
-
- /**
- * Connects to the remote media player on the receiver
- * @throws IllegalStateException
- * @throws IOException
- */
- private void connectRemoteMediaPlayer() throws IllegalStateException, IOException
- {
- Cast.CastApi.setMessageReceivedCallbacks(mApiClient, mRemoteMediaPlayer.getNamespace(), mRemoteMediaPlayer);
-
- mRemoteMediaPlayer.requestStatus(mApiClient)
- .setResultCallback(connectRemoteMediaPlayerCallback);
- }
-
- /**
- * launchApplication callback
- */
- private ResultCallback launchApplicationResultCallback = new ResultCallback()
- {
- @Override
- public void onResult(ApplicationConnectionResult result)
- {
- ApplicationMetadata metadata = result.getApplicationMetadata();
- ChromecastSession.this.sessionId = result.getSessionId();
- ChromecastSession.this.displayName = metadata.getName();
- ChromecastSession.this.appImages = metadata.getImages();
-
- Status status = result.getStatus();
-
- if (status.isSuccess())
- {
- try
- {
- ChromecastSession.this.launchCallback.onSuccess(ChromecastSession.this);
- connectRemoteMediaPlayer();
- ChromecastSession.this.isConnected = true;
- }
- catch (IllegalStateException e)
- {
- e.printStackTrace();
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- else
- {
- ChromecastSession.this.isConnected = false;
- }
- }
- };
-
- /**
- * joinApplication callback
- */
- private ResultCallback joinApplicationResultCallback = new ResultCallback()
- {
- @Override
- public void onResult(ApplicationConnectionResult result)
- {
- Status status = result.getStatus();
-
- if (status.isSuccess())
- {
- try
- {
- ApplicationMetadata metadata = result.getApplicationMetadata();
- ChromecastSession.this.sessionId = result.getSessionId();
- ChromecastSession.this.displayName = metadata.getName();
- ChromecastSession.this.appImages = metadata.getImages();
-
- ChromecastSession.this.joinSessionCallback.onSuccess(ChromecastSession.this);
- connectRemoteMediaPlayer();
- ChromecastSession.this.isConnected = true;
- }
- catch (IllegalStateException e)
- {
- e.printStackTrace();
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- else
- {
- ChromecastSession.this.joinSessionCallback.onError(status.toString());
- ChromecastSession.this.isConnected = false;
- }
- }
- };
-
- /**
- * connectRemoteMediaPlayer callback
- */
- private ResultCallback connectRemoteMediaPlayerCallback = new ResultCallback()
- {
- @Override
- public void onResult(MediaChannelResult result)
- {
- if (result.getStatus().isSuccess())
- {
- ChromecastSession.this.onMediaUpdatedListener.onMediaUpdated(true, ChromecastSession.this.createMediaObject());
- /*ChromecastSession.this.onMediaUpdatedListener.onMediaLoaded(ChromecastSession.this.createMediaObject());*/
- }
- else
- {
- System.out.println("Failed to request status.");
- }
- }
- };
-
- /**
- * Creates a JSON representation of this session
- * @return
- */
- public JSONObject createSessionObject()
- {
- JSONObject out = new JSONObject();
-
- try
- {
- out.put("appId", this.appId);
-
- if (this.appImages != null)
- {
- JSONArray appImages = new JSONArray();
-
- for(WebImage o : this.appImages)
- {
- appImages.put(o.toString());
- }
- }
-
- out.put("appImages", appImages);
- out.put("sessionId", this.sessionId);
- out.put("displayName", this.displayName);
-
- JSONObject receiver = new JSONObject();
- receiver.put("friendlyName", this.device.getFriendlyName());
- receiver.put("label", this.device.getDeviceId());
-
- JSONObject volume = new JSONObject();
-
- try
- {
- volume.put("level", Cast.CastApi.getVolume(mApiClient));
- volume.put("muted", Cast.CastApi.isMute(mApiClient));
- }
- catch(Exception e)
- {
- //
- }
-
- receiver.put("volume", volume);
-
- out.put("receiver", receiver);
-
- }
- catch(JSONException e)
- {
- //
- }
-
- return out;
- }
-
- /**
- * Creates a JSON representation of the current playing media
- * @return
- */
- private JSONObject createMediaObject()
- {
- JSONObject out = new JSONObject();
- JSONObject objInfo = new JSONObject();
-
- MediaStatus mediaStatus = mRemoteMediaPlayer.getMediaStatus();
-
- if (mediaStatus == null)
- {
- return out;
- }
-
- MediaInfo mediaInfo = mediaStatus.getMediaInfo();
-
- try
- {
- out.put("media", objInfo);
- out.put("mediaSessionId", 1);
- out.put("sessionId", this.sessionId);
- out.put("currentTime", mediaStatus.getStreamPosition() / 1000.0);
- out.put("playbackRate", mediaStatus.getPlaybackRate());
- out.put("customData", mediaStatus.getCustomData());
-
- switch(mediaStatus.getPlayerState())
- {
- case MediaStatus.PLAYER_STATE_BUFFERING:
- out.put("playerState", "BUFFERING"); break;
- case MediaStatus.PLAYER_STATE_IDLE:
- out.put("playerState", "IDLE"); break;
- case MediaStatus.PLAYER_STATE_PAUSED:
- out.put("playerState", "PAUSED"); break;
- case MediaStatus.PLAYER_STATE_PLAYING:
- out.put("playerState", "PLAYING"); break;
- case MediaStatus.PLAYER_STATE_UNKNOWN:
- out.put("playerState", "UNKNOWN"); break;
- }
-
- switch (mediaStatus.getIdleReason())
- {
- case MediaStatus.IDLE_REASON_CANCELED:
- out.put("idleReason", "canceled"); break;
- case MediaStatus.IDLE_REASON_ERROR:
- out.put("idleReason", "error"); break;
- case MediaStatus.IDLE_REASON_FINISHED:
- out.put("idleReason", "finished"); break;
- case MediaStatus.IDLE_REASON_INTERRUPTED:
- out.put("idleReason", "iterrupted"); break;
- case MediaStatus.IDLE_REASON_NONE:
- out.put("idleReason", "none"); break;
- }
-
- JSONObject volume = new JSONObject();
- volume.put("level", mediaStatus.getStreamVolume());
- volume.put("muted", mediaStatus.isMute());
-
- out.put("volume", volume);
-
- try
- {
- objInfo.put("duration", mediaInfo.getStreamDuration() / 1000.0);
-
- switch(mediaInfo.getStreamType())
- {
- case MediaInfo.STREAM_TYPE_BUFFERED:
- objInfo.put("streamType", "buffered"); break;
- case MediaInfo.STREAM_TYPE_LIVE:
- objInfo.put("streamType", "live"); break;
- case MediaInfo.STREAM_TYPE_NONE:
- objInfo.put("streamType", "other"); break;
- }
- }
- catch (Exception e)
- {
- //
- }
-
- }
- catch(JSONException e)
- {
- //
- }
-
- return out;
- }
-
-
-
- /* GoogleApiClient.ConnectionCallbacks implementation
- * Called when we successfully connect to the API
- * (non-Javadoc)
- * @see com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks#onConnected(android.os.Bundle)
- */
- @Override
- public void onConnected(Bundle connectionHint)
- {
- if (this.joinInsteadOfConnecting)
- {
- this.joinApplication();
- }
- else
- {
- this.launchApplication();
- }
- }
-
-
- /* GoogleApiClient.ConnectionCallbacks implementation
- * (non-Javadoc)
- * @see com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks#onConnectionSuspended(android.os.Bundle)
- */
- @Override
- public void onConnectionSuspended(int cause)
- {
- if (this.onSessionUpdatedListener != null)
- {
- this.isConnected = false;
- this.onSessionUpdatedListener.onSessionUpdated(false, this.createSessionObject());
- }
- }
-
- /*
- * GoogleApiClient.OnConnectionFailedListener implementation
- * When Google API fails to connect.
- * (non-Javadoc)
- * @see com.google.android.gms.common.GooglePlayServicesClient.OnConnectionFailedListener#onConnectionFailed(com.google.android.gms.common.ConnectionResult)
- */
- @Override
- public void onConnectionFailed(ConnectionResult result)
- {
- if (this.launchCallback != null)
- {
- this.isConnected = false;
- this.launchCallback.onError("channel_error");
- }
- }
-
- /**
- * Cast.Listener implementation
- * When Chromecast application status changed
- */
- @Override
- public void onApplicationStatusChanged()
- {
- if (this.onSessionUpdatedListener != null)
- {
- ChromecastSession.this.isConnected = true;
- this.onSessionUpdatedListener.onSessionUpdated(true, createSessionObject());
- }
- }
-
- /**
- * Cast.Listener implementation
- * When the volume is changed on the Chromecast
- */
- @Override
- public void onVolumeChanged()
- {
- if (this.onSessionUpdatedListener != null)
- {
- this.onSessionUpdatedListener.onSessionUpdated(true, createSessionObject());
- }
- }
-
- /**
- * Cast.Listener implementation
- * When the application is disconnected
- */
- @Override
- public void onApplicationDisconnected(int errorCode)
- {
- if (this.onSessionUpdatedListener != null)
- {
- this.isConnected = false;
- this.onSessionUpdatedListener.onSessionUpdated(false, this.createSessionObject());
- }
- }
-
-
- @Override
- public void onMetadataUpdated()
- {
- if (this.onMediaUpdatedListener != null)
- {
- this.onMediaUpdatedListener.onMediaUpdated(true, this.createMediaObject());
- }
- }
-
-
- @Override
- public void onStatusUpdated()
- {
- if (this.onMediaUpdatedListener != null)
- {
- this.onMediaUpdatedListener.onMediaUpdated(true, this.createMediaObject());
- }
- }
-
- /// GETTERS
- public String getSessionId()
- {
- return this.sessionId;
- }
-
- @Override
- public void onMessageReceived(CastDevice castDevice, String namespace, String message)
- {
- if (this.onSessionUpdatedListener != null) {
- this.onSessionUpdatedListener.onMessage(this, namespace, message);
- }
- }
-}
diff --git a/android/src/com/mesmotronic/ane/aircast/ChromecastSessionCallback.java b/android/src/com/mesmotronic/ane/aircast/ChromecastSessionCallback.java
deleted file mode 100644
index d68e6c0..0000000
--- a/android/src/com/mesmotronic/ane/aircast/ChromecastSessionCallback.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.mesmotronic.ane.aircast;
-
-public abstract class ChromecastSessionCallback
-{
- public void onSuccess()
- {
- onSuccess(null);
- }
-
- abstract void onSuccess(Object object);
- abstract void onError(String reason);
-}
\ No newline at end of file
diff --git a/build/android/library.swf b/build/android/library.swf
deleted file mode 100644
index ca90739..0000000
Binary files a/build/android/library.swf and /dev/null differ
diff --git a/build/build.cmd b/build/build.cmd
index 9012b56..bc14acf 100644
--- a/build/build.cmd
+++ b/build/build.cmd
@@ -1,13 +1,9 @@
@echo off
-copy ..\android\bin\aircast-jar.jar .\android\
-
adt ^
-package ^
-target ane ../example/libs/AirCast.ane extension.xml ^
-swc ../swc/bin/aircast-lib.swc ^
- -platform Android-ARM -C android . ^
- -platform Android-x86 -C android . ^
-platform iPhone-ARM -C ios . ^
-platform default -C default .
diff --git a/build/extension.xml b/build/extension.xml
index ebf7075..4b3bebd 100755
--- a/build/extension.xml
+++ b/build/extension.xml
@@ -12,22 +12,6 @@
AirCastFinalizer
-
-
-
- aircast-jar.jar
- com.mesmotronic.ane.aircast.AirCastExtension
- com.mesmotronic.ane.aircast.AirCastExtension
-
-
-
-
-
- aircast-jar.jar
- com.mesmotronic.ane.aircast.AirCastExtension
- com.mesmotronic.ane.aircast.AirCastExtension
-
-