diff options
author | Bilal Alsharifi <bilal.alsharifi@gmail.com> | 2020-06-02 15:53:26 -0400 |
---|---|---|
committer | Bilal Alsharifi <bilal.alsharifi@gmail.com> | 2020-06-02 15:53:26 -0400 |
commit | 050ae26425751b3beaa0995f3724c22ebe05351f (patch) | |
tree | 209a167b38c3ae862b10366b9c966a7856d7f134 | |
parent | c572b8b3581c45abcbd4c9dd3fbc0877841fb290 (diff) | |
download | sdl_android-050ae26425751b3beaa0995f3724c22ebe05351f.tar.gz |
Add basic NAV & PCM support to BaseLifecycleManager
-rw-r--r-- | base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java | 305 |
1 files changed, 295 insertions, 10 deletions
diff --git a/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java b/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java index 3f7f6c73e..0e62032b5 100644 --- a/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java +++ b/base/src/main/java/com/smartdevicelink/managers/lifecycle/BaseLifecycleManager.java @@ -99,7 +99,11 @@ import com.smartdevicelink.util.Version; import java.util.HashMap; import java.util.List; import java.util.Vector; +import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; +import java.util.concurrent.ScheduledExecutorService; abstract class BaseLifecycleManager { @@ -134,6 +138,22 @@ abstract class BaseLifecycleManager { Version minimumProtocolVersion; Version minimumRPCVersion; + private static final int RESPONSE_WAIT_TIME = 2000; + private ISdlServiceListener navServiceListener; + private boolean navServiceStartResponseReceived = false; + private boolean navServiceStartResponse = false; + private List<String> navServiceStartRejectedParams = null; + private boolean pcmServiceStartResponseReceived = false; + private boolean pcmServiceStartResponse = false; + private List<String> pcmServiceStartRejectedParams = null; + private boolean navServiceEndResponseReceived = false; + private boolean navServiceEndResponse = false; + private boolean pcmServiceEndResponseReceived = false; + private boolean pcmServiceEndResponse = false; + private boolean rpcProtectedResponseReceived = false; + private boolean rpcProtectedStartResponse = false; + + BaseLifecycleManager(AppConfig appConfig, BaseTransportConfig config, LifecycleListener listener){ this.lifecycleListener = listener; @@ -897,7 +917,14 @@ abstract class BaseLifecycleManager { @Override public void onProtocolSessionStartedNACKed(SessionType sessionType, byte sessionID, byte version, String correlationID, List<String> rejectedParams) { - Log.w(TAG, "onProtocolSessionStartedNACKed " + sessionID); + Log.w(TAG, sessionType + " onProtocolSessionStartedNACKed " + sessionID + " RejectedParams: " + rejectedParams); + + if (sessionType.eq(SessionType.NAV)) { + NavServiceStartedNACK(rejectedParams); + } + else if (sessionType.eq(SessionType.PCM)) { + AudioServiceStartedNACK(rejectedParams); + } } @Override @@ -943,6 +970,10 @@ abstract class BaseLifecycleManager { } + } else if (sessionType.eq(SessionType.NAV)) { + NavServiceStarted(); + } else if (sessionType.eq(SessionType.PCM)) { + AudioServiceStarted(); } else { lifecycleListener.onServiceStarted(sessionType); } @@ -951,12 +982,22 @@ abstract class BaseLifecycleManager { @Override public void onProtocolSessionEnded(SessionType sessionType, byte sessionID, String correlationID) { - + if (sessionType.eq(SessionType.NAV)) { + NavServiceEnded(); + } + else if (sessionType.eq(SessionType.PCM)) { + AudioServiceEnded(); + } } @Override public void onProtocolSessionEndedNACKed(SessionType sessionType, byte sessionID, String correlationID) { - + if (sessionType.eq(SessionType.NAV)) { + NavServiceEndedNACK(); + } + else if (sessionType.eq(SessionType.PCM)) { + AudioServiceEndedNACK(); + } } @Override @@ -1014,13 +1055,16 @@ abstract class BaseLifecycleManager { @Override public void startVideoService(VideoStreamingParameters parameters, boolean encrypted) { - DebugTool.logWarning("startVideoService is not currently implemented"); + if(isConnected()){ + BaseLifecycleManager.this.startVideoService(encrypted,parameters); + } } @Override public void stopVideoService() { - DebugTool.logWarning("stopVideoService is not currently implemented"); - + if(isConnected()){ + BaseLifecycleManager.this.endVideoStream(); + } } @Override @@ -1036,13 +1080,16 @@ abstract class BaseLifecycleManager { @Override public void startAudioService(boolean encrypted) { - DebugTool.logWarning("startAudioService is not currently implemented"); - + if(isConnected()){ + BaseLifecycleManager.this.startService(SessionType.PCM, encrypted); + } } @Override public void stopAudioService() { - DebugTool.logWarning("stopAudioService is not currently implemented"); + if(isConnected()){ + BaseLifecycleManager.this.endAudioStream(); + } } @Override @@ -1054,7 +1101,6 @@ abstract class BaseLifecycleManager { @Override public void sendRPCRequest(RPCRequest message) { BaseLifecycleManager.this.sendRPCMessagePrivate(message); - } @Override @@ -1469,4 +1515,243 @@ abstract class BaseLifecycleManager { } } } + + + + + ///////////////////////////// + + /** + * Try to open a video service by using the video streaming parameters supplied. + * <p> + * Only information from codecs, width and height are used during video format negotiation. + * + * @param isEncrypted Specify true if packets on this service have to be encrypted + * @param parameters VideoStreamingParameters that are desired. Does not guarantee this is what will be accepted. + * @return If the service is opened successfully, an instance of VideoStreamingParams is + * returned which contains accepted video format. If the service is opened with legacy + * mode (i.e. without any negotiation) then an instance of VideoStreamingParams is + * returned. If the service was not opened then null is returned. + */ + private VideoStreamingParameters tryStartVideoStream(boolean isEncrypted, VideoStreamingParameters parameters) { + if (session == null) { + DebugTool.logWarning("SdlSession is not created yet."); + return null; + } + if (getProtocolVersion() != null && getProtocolVersion().getMajor() >= 5 && !systemCapabilityManager.isCapabilitySupported(SystemCapabilityType.VIDEO_STREAMING)) { + DebugTool.logWarning("Module doesn't support video streaming."); + return null; + } + if (parameters == null) { + DebugTool.logWarning("Video parameters were not supplied."); + return null; + } + + if (!navServiceStartResponseReceived || !navServiceStartResponse //If we haven't started the service before + || (navServiceStartResponse && isEncrypted && !session.isServiceProtected(SessionType.NAV))) { //Or the service has been started but we'd like to start an encrypted one + session.setDesiredVideoParams(parameters); + + navServiceStartResponseReceived = false; + navServiceStartResponse = false; + navServiceStartRejectedParams = null; + + session.startService(SessionType.NAV, session.getSessionId(), isEncrypted); + addNavListener(); + FutureTask<Void> fTask = createFutureTask(new CallableMethod(RESPONSE_WAIT_TIME)); + ScheduledExecutorService scheduler = createScheduler(); + scheduler.execute(fTask); + + //noinspection StatementWithEmptyBody + while (!navServiceStartResponseReceived && !fTask.isDone()) ; + scheduler.shutdown(); + } + + if (navServiceStartResponse) { + if (getProtocolVersion() != null && getProtocolVersion().getMajor() < 5) { //Versions 1-4 do not support streaming parameter negotiations + session.setAcceptedVideoParams(parameters); + } + return session.getAcceptedVideoParams(); + } + + return null; + } + + private void addNavListener() { + // videos may be started and stopped. Only add this once + if (navServiceListener == null) { + + navServiceListener = new ISdlServiceListener() { + @Override + public void onServiceStarted(SdlSession session, SessionType type, boolean isEncrypted) { + } + + @Override + public void onServiceEnded(SdlSession session, SessionType type) { + // reset nav flags so nav can start upon the next transport connection + resetNavStartFlags(); + // propagate notification up to proxy listener so the developer will know that the service is ended + if (lifecycleListener != null) { + lifecycleListener.onServiceEnded(type); + } + } + + @Override + public void onServiceError(SdlSession session, SessionType type, String reason) { + // if there is an error reset the flags so that there is a chance to restart streaming + resetNavStartFlags(); + } + }; + session.addServiceListener(SessionType.NAV, navServiceListener); + } + } + + /** + * This method will try to start the video service with the requested parameters. + * When it returns it will attempt to store the accepted parameters if available. + * + * @param isEncrypted if the service should be encrypted + * @param parameters the desiered video streaming parameters + */ + private void startVideoService(boolean isEncrypted, VideoStreamingParameters parameters) { + if (session == null) { + DebugTool.logWarning("SdlSession is not created yet."); + return; + } + if (!session.getIsConnected()) { + DebugTool.logWarning("Connection is not available."); + return; + } + + session.setDesiredVideoParams(parameters); + + tryStartVideoStream(isEncrypted, parameters); + } + + + /** + * Closes the opened video service (serviceType 11) + * + * @return true if the video service is closed successfully, return false otherwise + */ + private boolean endVideoStream() { + if (session == null) { + return false; + } + + navServiceEndResponseReceived = false; + navServiceEndResponse = false; + session.stopVideoStream(); + + FutureTask<Void> fTask = createFutureTask(new CallableMethod(RESPONSE_WAIT_TIME)); + ScheduledExecutorService scheduler = createScheduler(); + scheduler.execute(fTask); + + //noinspection StatementWithEmptyBody + while (!navServiceEndResponseReceived && !fTask.isDone()) ; + scheduler.shutdown(); + + return navServiceEndResponse; + } + + private void startService(SessionType serviceType, boolean isEncrypted) { + session.startService(serviceType, session.getSessionId(), isEncrypted); + } + + + /** + * Closes the opened audio service (serviceType 10) + * + * @return true if the audio service is closed successfully, return false otherwise + */ + private boolean endAudioStream() { + if (session == null || !session.getIsConnected()) return false; + + pcmServiceEndResponseReceived = false; + pcmServiceEndResponse = false; + session.stopAudioStream(); + + FutureTask<Void> fTask = createFutureTask(new CallableMethod(RESPONSE_WAIT_TIME)); + ScheduledExecutorService scheduler = createScheduler(); + scheduler.execute(fTask); + + //noinspection StatementWithEmptyBody + while (!pcmServiceEndResponseReceived && !fTask.isDone()) ; + scheduler.shutdown(); + + return pcmServiceEndResponse; + } + + private class CallableMethod implements Callable<Void> { + private final long waitTime; + + public CallableMethod(int timeInMillis) { + this.waitTime = timeInMillis; + } + + @Override + public Void call() { + try { + Thread.sleep(waitTime); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return null; + } + } + + private FutureTask<Void> createFutureTask(CallableMethod callMethod) { + return new FutureTask<>(callMethod); + } + + private ScheduledExecutorService createScheduler() { + return Executors.newSingleThreadScheduledExecutor(); + } + + private void NavServiceStarted() { + navServiceStartResponseReceived = true; + navServiceStartResponse = true; + } + + private void NavServiceStartedNACK(List<String> rejectedParams) { + navServiceStartResponseReceived = true; + navServiceStartResponse = false; + navServiceStartRejectedParams = rejectedParams; + } + + private void AudioServiceStarted() { + pcmServiceStartResponseReceived = true; + pcmServiceStartResponse = true; + } + + private void AudioServiceStartedNACK(List<String> rejectedParams) { + pcmServiceStartResponseReceived = true; + pcmServiceStartResponse = false; + pcmServiceStartRejectedParams = rejectedParams; + } + + private void NavServiceEnded() { + navServiceEndResponseReceived = true; + navServiceEndResponse = true; + } + + private void NavServiceEndedNACK() { + navServiceEndResponseReceived = true; + navServiceEndResponse = false; + } + + private void AudioServiceEnded() { + pcmServiceEndResponseReceived = true; + pcmServiceEndResponse = true; + } + + private void AudioServiceEndedNACK() { + pcmServiceEndResponseReceived = true; + pcmServiceEndResponse = false; + } + + private void resetNavStartFlags() { + navServiceStartResponseReceived = false; + navServiceStartResponse = false; + navServiceStartRejectedParams = null; + } } |