package com.kaltura.playersdk.casting;
import android.content.Context;
import android.support.annotation.NonNull;
import com.google.android.gms.cast.framework.CastContext;
import com.google.android.gms.cast.framework.CastSession;
import com.google.android.gms.cast.framework.CastStateListener;
import com.google.android.gms.cast.framework.Session;
import com.google.android.gms.cast.framework.SessionManager;
import com.google.android.gms.cast.framework.SessionManagerListener;
import com.google.android.gms.common.api.ResultCallbacks;
import com.google.android.gms.common.api.Status;
import com.kaltura.playersdk.interfaces.KCastMediaRemoteControl;
import com.kaltura.playersdk.interfaces.KCastProvider;
import com.kaltura.playersdk.players.KChromeCastPlayer;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import static com.kaltura.playersdk.utils.LogUtils.LOGD;
import static com.kaltura.playersdk.utils.LogUtils.LOGE;
/**
* Created by Gleb on 9/13/16.
*/
public class KCastProviderV3Impl implements KCastProvider {
private static final String TAG = "KCastProviderImpl";
public static String nameSpace = "urn:x-cast:com.kaltura.cast.player";
private SessionManager mSessionManager;
private CastSession mCastSession;
private CastContext mCastContext;
private KCastProviderListener mProviderListener;
private KCastMediaRemoteControl mCastMediaRemoteControl;
private KCastKalturaChannel mChannel;
private KCastInternalListener mInternalListener;
private SessionManagerListener mSessionManagerListener = null;
private Context mContext;
private String mCastAppId;
private boolean mApplicationStarted;
private boolean isReconnedted = true;
private String mCastLogoUrl = "";
private boolean isInSession = false;
private boolean appInbg = false;
private int numOfConnectedSenders = 0;
//private boolean isPlayAfterEnded = false;
//private String[] currentMediaParams;
//@NonNull private KPlayerListener mPlayerListener = noopPlayerListener();
public KCastProviderV3Impl(Context context, String castAppId, String logoUrl) {
mContext = context;
mCastContext = CastContext.getSharedInstance(context);
mCastLogoUrl = logoUrl;
//mCastContext.registerLifecycleCallbacksBeforeIceCreamSandwich(this, savedInstanceState);
mSessionManager = mCastContext.getSessionManager();
mSessionManagerListener = createProviderSessionManagerListener();
mSessionManager.addSessionManagerListener(mSessionManagerListener);
mCastSession = mSessionManager.getCurrentCastSession();
mCastAppId = castAppId;
}
@Override
public void setCastProviderContext(Context newContext) {
mContext = newContext;
mCastContext = CastContext.getSharedInstance(newContext);
mSessionManager = mCastContext.getSessionManager();
if (mSessionManagerListener != null) {
mSessionManager.removeSessionManagerListener(mSessionManagerListener);
}
mSessionManagerListener = createProviderSessionManagerListener();
mSessionManager.addSessionManagerListener(mSessionManagerListener);
mCastSession = mSessionManager.getCurrentCastSession();
}
@Override
public int getNumOfConnectedSenders() {
return numOfConnectedSenders;
}
public void setNumOfConnectedSenders(int numOfConnectedSenders) {
this.numOfConnectedSenders = numOfConnectedSenders;
}
public void addCastStateListener(CastStateListener castStateListener) {
mCastContext.addCastStateListener(castStateListener);
}
public void removeCastStateListener(CastStateListener castStateListener) {
mCastContext.removeCastStateListener(castStateListener);
}
public void setInternalListener(KCastInternalListener internalListener) {
mInternalListener = internalListener;
}
public String getCastLogoUrl() {
return mCastLogoUrl;
}
public void setCastLogoUrl(String mCastLogoUrl) {
this.mCastLogoUrl = mCastLogoUrl;
}
public KCastProviderListener getProviderListener() {
return mProviderListener;
}
// private KPlayerListener noopPlayerListener() {
// return new KPlayerListener() {
// public void eventWithValue(KPlayer player, String eventName, String eventValue) {}
// public void eventWithJSON(KPlayer player, String eventName, String jsonValue) {}
// public void asyncEvaluate(String expression, String expressionID, PlayerViewController.EvaluateListener evaluateListener) {}
// public void contentCompleted(KPlayer currentPlayer) {}
// };
// }
// public void setPlayerListener(@NonNull KPlayerListener listener) {
// mPlayerListener = listener;
// }
@Override
public void init(Context context) {
setCastProviderContext(context);
}
@Override
public void startReceiver(Context context, boolean guestModeEnabled) {
mCastSession = mSessionManager.getCurrentCastSession();
if (mChannel == null) {
mChannel = new KCastKalturaChannel(nameSpace, new KCastKalturaChannel.KCastKalturaChannelListener() {
@Override
public void readyForMedia(final String[] params) {
//if (!isRecconected()) {
sendMessage("{\"type\":\"hide\",\"target\":\"logo\"}");
//}
// Receiver send the new content
if (params != null) {
//currentMediaParams = params;
mCastMediaRemoteControl = new KChromeCastPlayer(mCastSession);
((KChromeCastPlayer) mCastMediaRemoteControl).setMediaInfoParams(params);
if (mInternalListener != null) {
mInternalListener.onStartCasting((KChromeCastPlayer) mCastMediaRemoteControl);
}
}
}
@Override
public void ccOnSenderConnected(int numOfSendersConnected) {
LOGD(TAG, "ccOnSenderConnected :" + numOfSendersConnected);
setNumOfConnectedSenders(numOfSendersConnected);
}
@Override
public void ccOnSenderDisconnected(int numOfSendersConnected) {
LOGD(TAG, "ccOnSenderDisconnected :" + numOfSendersConnected);
setNumOfConnectedSenders(numOfSendersConnected);
}
@Override
public void ccUpdateAdDuration(int adDuration) {
//LOGD(TAG, "ccUpdateAdDuration :" + adDuration);
//mPlayerListener.eventWithValue(null, KPlayerListener.AdDurationChangeKey, String.valueOf(adDuration));
}
@Override
public void ccUserInitiatedPlay() {
// if (isPlayAfterEnded) {
// mCastMediaRemoteControl = new KChromeCastPlayer(mCastSession);
// ((KChromeCastPlayer) mCastMediaRemoteControl).setMediaInfoParams(currentMediaParams);
// if (mInternalListener != null) {
// mInternalListener.onStartCasting((KChromeCastPlayer) mCastMediaRemoteControl);
// }
// sendMessage("{\"type\":\"hide\",\"target\":\"logo\"}");
// isPlayAfterEnded = false;
// }
}
@Override
public void ccReceiverAdOpen() {
LOGD(TAG, "ccReceiverAdOpen");
sendMessage("{\"type\":\"hide\",\"target\":\"logo\"}");
mProviderListener.onCastReceiverAdOpen();
}
@Override
public void ccReceiverAdComplete() {
LOGD(TAG, "ccReceiverAdComplete");
mProviderListener.onCastReceiverAdComplete();
}
@Override
public void textTeacksRecived(HashMap<String, Integer> textTrackHash) {
if (getCastMediaRemoteControl() != null) {
getCastMediaRemoteControl().setTextTracks(textTrackHash);
}
}
@Override
public void videoTracksReceived(List<Integer> videoTracksList) {
if (getCastMediaRemoteControl() != null) {
getCastMediaRemoteControl().setVideoTracks(videoTracksList);
}
}
@Override
public void onCastReceiverError(String errorMsg, int errorCode) {
mProviderListener.onCastReceiverError(errorMsg, errorCode);
}
});
}
if (mCastSession != null) {
try {
mCastSession.setMessageReceivedCallbacks(nameSpace, mChannel);
} catch (IOException e) {
LOGE(TAG, "Exception while creating channel", e);
}
if (!isReconnected()) {
if (!"".equals(mCastLogoUrl)) {
mCastSession.sendMessage(nameSpace, "{\"type\": \"setLogo\", \"logo\": \"" + mCastLogoUrl + "\"}");
}
if (!isCasting()) {
sendMessage("{\"type\":\"show\",\"target\":\"logo\"}");
}
}
mApplicationStarted = true;
}
}
@Override
public void startReceiver(Context context) {
startReceiver(context, false);
}
@Override
public void showLogo() {
sendMessage("{\"type\":\"show\",\"target\":\"logo\"}");
}
@Override
public void hideLogo() {
sendMessage("{\"type\":\"hide\",\"target\":\"logo\"}");
}
@Override
public void disconnectFromCastDevice() {
if (mInternalListener != null) {
//mInternalListener.onCastStateChanged("hideConnectingMessage");
mInternalListener.onCastStateChanged("chromecastDeviceDisConnected");
mInternalListener.onStopCasting(appInbg);
if (getNumOfConnectedSenders() == 1) {
setNumOfConnectedSenders(0);
}
}
teardown();
}
@Override
public void setAppBackgroundState(boolean appBgState) {
appInbg = appBgState;
}
@Override
public boolean getAppBackgroundState() {
return appInbg;
}
@Override
public KCastDevice getSelectedCastDevice() {
if (mCastSession != null) {
return new KCastDevice(mCastSession.getCastDevice());
}
return null;
}
@Override
public void setKCastProviderListener(KCastProviderListener listener) {
mProviderListener = listener;
}
@Override
public KCastMediaRemoteControl getCastMediaRemoteControl() {
return mCastMediaRemoteControl;
}
@Override
public boolean isReconnected() {
return isReconnedted;
}
@Override
public boolean isConnected() {
if (mCastSession != null) {
return mCastSession.isConnected();
}
if (CastContext.getSharedInstance(mContext) != null && CastContext.getSharedInstance(mContext).getSessionManager() != null) {
mCastSession = CastContext.getSharedInstance(mContext).getSessionManager().getCurrentCastSession();
if (mCastSession != null) {
return mCastSession.isConnected();
}
}
return false;
}
@Override
public boolean isCasting() {
if (mCastSession != null && mCastSession.getRemoteMediaClient() != null) {
return mCastSession.getRemoteMediaClient().isPlaying() || mCastSession.getRemoteMediaClient().isPaused() || mCastSession.getRemoteMediaClient().getMediaInfo() != null;
}
return false;
}
@Override
public long getStreamDuration() {
if (mCastSession != null && mCastSession.getRemoteMediaClient() != null) {
return mCastSession.getRemoteMediaClient().getStreamDuration();
}
return -1;
}
@Override
public String getSessionEntryID() {
String sessionEntryID = null;
if (mCastSession != null && mCastSession.getRemoteMediaClient() != null &&
mCastSession.getRemoteMediaClient().getMediaInfo() != null &&
mCastSession.getRemoteMediaClient().getMediaInfo().getMetadata() != null) {
sessionEntryID = mCastSession.getRemoteMediaClient().getMediaInfo().getMetadata().getString(KChromeCastPlayer.KEY_ENTRY_ID);
}
if (sessionEntryID != null) {
LOGD(TAG, "sessionEntryID = " + sessionEntryID);
} else {
LOGD(TAG, "sessionEntryID is not set");
}
return sessionEntryID;
}
public void sendMessage(final String message) {
if (mCastSession != null) {
mCastSession.sendMessage(nameSpace, message).setResultCallback(new ResultCallbacks<Status>() {
@Override
public void onSuccess(@NonNull Status status) {
LOGD(TAG, "Message Sent OK: namespace:" + nameSpace + " message:" + message);
}
@Override
public void onFailure(@NonNull Status status) {
LOGE(TAG, "Sending message failed");
}
});
}
}
public CastSession getCastSession() {
return mCastSession;
}
public void removeSessionManagerListener() {
if (mSessionManagerListener != null) {
mSessionManager.removeSessionManagerListener(mSessionManagerListener);
mSessionManagerListener = null;
}
}
private void teardown() {
if (mCastSession != null) {
LOGD(TAG, "START TEARDOWN mApiClient.isConnected() = " + mCastSession.isConnected() + " mApiClient.isConnecting() = " + mCastSession.isConnecting()) ;
if (mCastSession != null) {
if (mCastSession.getRemoteMediaClient() != null) {
mCastSession.getRemoteMediaClient().removeListener(null);
try {
mCastSession.removeMessageReceivedCallbacks(nameSpace);
} catch (IOException e) {
e.printStackTrace();
}
}
}
if (mApplicationStarted) {
boolean isConnected = mCastSession.isConnected();
boolean isConnecting = mCastSession.isConnecting();
if (isConnected || isConnecting) {
try {
if (isConnected) {
mCastSession.getRemoteMediaClient().stop();
}
if (mChannel != null) {
mCastSession.removeMessageReceivedCallbacks(nameSpace);
mChannel = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
mApplicationStarted = false;
}
mCastSession = null;
}
}
private SessionManagerListener createProviderSessionManagerListener() {
return new SessionManagerListener() {
@Override
public void onSessionStarting(Session session) {
LOGD(TAG, "SessionManagerListener onSessionStarting");
}
@Override
public void onSessionStarted(Session session, String s) {
isReconnedted = false;
if (!isInSession) {
LOGD(TAG, "SessionManagerListener onSessionStarted");
startReceiver(mContext);
}
isInSession = true;
}
@Override
public void onSessionStartFailed(Session session, int i) {
LOGD(TAG, "SessionManagerListener onSessionStartFailed");
isInSession = false;
}
@Override
public void onSessionEnding(Session session) {
LOGD(TAG, "SessionManagerListener onSessionEnding");
disconnectFromCastDevice();
isInSession = false;
}
@Override
public void onSessionEnded(Session session, int i) {
LOGD(TAG, "SessionManagerListener onSessionEnded");
if (isInSession) {
disconnectFromCastDevice();
isInSession = false;
}
}
@Override
public void onSessionResuming(Session session, String s) {
LOGD(TAG, "SessionManagerListener onSessionResuming");
}
@Override
public void onSessionResumed(Session session, boolean b) {
LOGD(TAG, "SessionManagerListener onSessionResumed");
isInSession = true;
}
@Override
public void onSessionResumeFailed(Session session, int i) {
LOGD(TAG, "SessionManagerListener onSessionResumeFailed");
disconnectFromCastDevice();
isInSession = false;
}
@Override
public void onSessionSuspended(Session session, int i) {
LOGD(TAG, "SessionManagerListener onSessionSuspended");
if (mCastSession != null && mCastSession.getRemoteMediaClient() != null) {
LOGD(TAG, "onSessionSuspended CURRENT POSITION = " + mCastSession.getRemoteMediaClient().getApproximateStreamPosition());
}
}
};
}
}