diff --git a/playkit/src/androidTest/java/com/kaltura/playkit/plugins/KalturaAnalyticsAndroidTest.java b/playkit/src/androidTest/java/com/kaltura/playkit/plugins/KalturaAnalyticsAndroidTest.java index b51706f7d..b5ce9722f 100644 --- a/playkit/src/androidTest/java/com/kaltura/playkit/plugins/KalturaAnalyticsAndroidTest.java +++ b/playkit/src/androidTest/java/com/kaltura/playkit/plugins/KalturaAnalyticsAndroidTest.java @@ -8,11 +8,11 @@ import com.kaltura.playkit.LogEvent; import com.kaltura.playkit.MessageBus; import com.kaltura.playkit.PKEvent; +import com.kaltura.playkit.PKMediaConfig; import com.kaltura.playkit.PKMediaEntry; import com.kaltura.playkit.PKMediaSource; import com.kaltura.playkit.PlayKitManager; import com.kaltura.playkit.Player; -import com.kaltura.playkit.PlayerConfig; import com.kaltura.playkit.PlayerEvent; import org.junit.Assert; @@ -66,13 +66,13 @@ private void setPluginConfigObject(){ } private void setMediaObject(){ - PlayerConfig config = new PlayerConfig(); + PKMediaConfig config = new PKMediaConfig(); PKMediaSource mediaSource = new PKMediaSource().setUrl("http://cdnapi.kaltura.com/p/1774581/sp/177458100/playManifest/entryId/1_mphei4ku/format/applehttp/tags/mbr/protocol/http/f/a.m3u8"); mediaSource.setId("516109"); ArrayList sourceList = new ArrayList<>(); sourceList.add(mediaSource); PKMediaEntry mediaEntryProvider = new PKMediaEntry().setId(entryId).setDuration(duration).setSources(sourceList); - config.media.setMediaEntry(mediaEntryProvider); + config.setMediaEntry(mediaEntryProvider); } @Test diff --git a/playkit/src/androidTest/java/com/kaltura/playkit/plugins/KalturaStatsAndroidTest.java b/playkit/src/androidTest/java/com/kaltura/playkit/plugins/KalturaStatsAndroidTest.java index 4f0408659..fb1eff3c3 100644 --- a/playkit/src/androidTest/java/com/kaltura/playkit/plugins/KalturaStatsAndroidTest.java +++ b/playkit/src/androidTest/java/com/kaltura/playkit/plugins/KalturaStatsAndroidTest.java @@ -8,10 +8,10 @@ import com.kaltura.playkit.LogEvent; import com.kaltura.playkit.MessageBus; import com.kaltura.playkit.PKEvent; +import com.kaltura.playkit.PKMediaConfig; import com.kaltura.playkit.PKMediaEntry; import com.kaltura.playkit.PKMediaSource; import com.kaltura.playkit.Player; -import com.kaltura.playkit.PlayerConfig; import com.kaltura.playkit.PlayerEvent; import org.junit.Assert; @@ -68,13 +68,13 @@ private void setPluginConfigObject(){ } private void setMediaObject(){ - PlayerConfig config = new PlayerConfig(); + PKMediaConfig config = new PKMediaConfig(); PKMediaSource mediaSource = new PKMediaSource().setUrl("http://cdnapi.kaltura.com/p/1774581/sp/177458100/playManifest/entryId/1_mphei4ku/format/applehttp/tags/mbr/protocol/http/f/a.m3u8"); mediaSource.setId("516109"); ArrayList sourceList = new ArrayList<>(); sourceList.add(mediaSource); PKMediaEntry mediaEntryProvider = new PKMediaEntry().setId(entryId).setDuration(duration).setSources(sourceList); - config.media.setMediaEntry(mediaEntryProvider); + config.setMediaEntry(mediaEntryProvider); } @Test diff --git a/playkit/src/androidTest/java/com/kaltura/playkit/plugins/PhoenixTvpapiAndroidTest.java b/playkit/src/androidTest/java/com/kaltura/playkit/plugins/PhoenixTvpapiAndroidTest.java index 4b676501c..30e799f00 100644 --- a/playkit/src/androidTest/java/com/kaltura/playkit/plugins/PhoenixTvpapiAndroidTest.java +++ b/playkit/src/androidTest/java/com/kaltura/playkit/plugins/PhoenixTvpapiAndroidTest.java @@ -8,10 +8,10 @@ import com.kaltura.playkit.LogEvent; import com.kaltura.playkit.MessageBus; import com.kaltura.playkit.PKEvent; +import com.kaltura.playkit.PKMediaConfig; import com.kaltura.playkit.PKMediaEntry; import com.kaltura.playkit.PKMediaSource; import com.kaltura.playkit.Player; -import com.kaltura.playkit.PlayerConfig; import com.kaltura.playkit.PlayerEvent; import org.junit.Assert; @@ -95,13 +95,13 @@ private void setPhoenixPluginConfig() { } private void setMediaObject() { - PlayerConfig config = new PlayerConfig(); + PKMediaConfig config = new PKMediaConfig(); PKMediaSource mediaSource = new PKMediaSource().setUrl("http://cdnapi.kaltura.com/p/1774581/sp/177458100/playManifest/entryId/1_mphei4ku/format/applehttp/tags/mbr/protocol/http/f/a.m3u8"); mediaSource.setId("516109"); ArrayList sourceList = new ArrayList<>(); sourceList.add(mediaSource); PKMediaEntry mediaEntryProvider = new PKMediaEntry().setId(entryId).setDuration(duration).setSources(sourceList); - config.media.setMediaEntry(mediaEntryProvider); + config.setMediaEntry(mediaEntryProvider); } @Test diff --git a/playkit/src/main/java/com/kaltura/playkit/LocalAssetsManager.java b/playkit/src/main/java/com/kaltura/playkit/LocalAssetsManager.java index 6077edc22..a0cd609a8 100644 --- a/playkit/src/main/java/com/kaltura/playkit/LocalAssetsManager.java +++ b/playkit/src/main/java/com/kaltura/playkit/LocalAssetsManager.java @@ -25,10 +25,11 @@ public class LocalAssetsManager { private static final PKLog log = PKLog.get("LocalAssetsManager"); + private static final String ASSET_ID_PREFIX = "assetId:"; private final Context context; private LocalDataStore localDataStore; - + private Handler mainHandler = new Handler(Looper.getMainLooper()); /** @@ -37,14 +38,16 @@ public class LocalAssetsManager { public interface AssetRegistrationListener { /** * Will notify about success. + * * @param localAssetPath - the path of the local asset. */ void onRegistered(String localAssetPath); /** * Will notify if registration process was not successful. + * * @param localAssetPath - the path of the local asset. - * @param error - error that occured during the registration process. + * @param error - error that occured during the registration process. */ void onFailed(String localAssetPath, Exception error); } @@ -65,6 +68,7 @@ public interface AssetRemovalListener { /** * Constructor which will create {@link DefaultLocalDataStore} + * * @param context - the application context. */ public LocalAssetsManager(Context context) { @@ -73,98 +77,119 @@ public LocalAssetsManager(Context context) { /** * Constructor with custom implementation of the {@link LocalDataStore} - * @param context - the application context. + * + * @param context - the application context. * @param localDataStore - custom implementation of {@link LocalDataStore} */ public LocalAssetsManager(Context context, LocalDataStore localDataStore) { this.context = context; this.localDataStore = localDataStore; - + MediaSupport.initialize(context); } - /** - * Register the asset. If the asset have drm protection it will store its keySetId in {@link LocalDataStore} - * @param mediaSource - the source to register. + * Register the asset. If the asset have drm protection it will store keySetId and {@link PKMediaFormat} in {@link LocalDataStore} + * If no drm available only {@link PKMediaFormat as byte[]} will be stored. + * + * @param mediaSource - the source to register. * @param localAssetPath - the url of the locally stored asset. - * @param assetId - the asset id. - * @param listener - notify about the success/fail after the completion of the registration process. + * @param assetId - the asset id. + * @param listener - notify about the success/fail after the completion of the registration process. */ public void registerAsset(@NonNull final PKMediaSource mediaSource, @NonNull final String localAssetPath, - @NonNull final String assetId, final AssetRegistrationListener listener) { + @NonNull final String assetId, final AssetRegistrationListener listener) { - // Preflight: check that all parameters are valid. - checkNotEmpty(mediaSource.getUrl(), "mediaSource.url"); - checkNotEmpty(localAssetPath, "localAssetPath"); - checkNotEmpty(assetId, "assetId"); + checkIfParamsAreValid(mediaSource.getUrl(), localAssetPath, assetId); if (!isOnline(context)) { - //TODO check with noam if it is alright to return an exception at this stage. listener.onFailed(localAssetPath, new Exception("Can't register/refresh when offline")); return; } - final PKDrmParams drmParams = findSupportedDrmParams(mediaSource); - + PKDrmParams drmParams = findSupportedDrmParams(mediaSource); + + PKMediaFormat mediaFormat = mediaSource.getMediaFormat(); + if(mediaFormat == null){ + listener.onFailed(localAssetPath, + new IllegalArgumentException("Can not register media, when PKMediaFormat and url of PKMediaSource not exist.")); + } + if (drmParams != null) { - doInBackground(new Runnable() { - @Override - public void run() { - try { - DrmAdapter drmAdapter = DrmAdapter.getDrmAdapter(drmParams.getScheme(), context, localDataStore); - String licenseUri = drmParams.getLicenseUri(); - drmAdapter.registerAsset(localAssetPath, assetId, licenseUri, listener); - - } catch (final IOException e) { - log.e("Error", e); - if (listener != null) { - mainHandler.post(new Runnable() { - @Override - public void run() { - listener.onFailed(localAssetPath, e); - } - }); - } - } - } - }); + registerDrmAsset(localAssetPath, assetId, mediaFormat, drmParams, listener); + } else { + registerClearAsset(localAssetPath, assetId, mediaFormat, listener); } } - private static PKDrmParams findSupportedDrmParams(@NonNull PKMediaSource mediaSource) { - for (PKDrmParams params : mediaSource.getDrmData()) { - switch (params.getScheme()) { - case WidevineCENC: - if (MediaSupport.widevineModular()) { - return params; + /** + * Will register the drm asset and store the keyset id and {@link PKMediaFormat} in local storage. + * + * @param localAssetPath - the local asset path of the asset. + * @param assetId - the asset id. + * @param mediaFormat - the media format converted to byte[]. + * @param drmParams - drm params of the media. + * @param listener - notify about the success/fail after the completion of the registration process. + */ + private void registerDrmAsset(final String localAssetPath, final String assetId, final PKMediaFormat mediaFormat, final PKDrmParams drmParams, final AssetRegistrationListener listener) { + doInBackground(new Runnable() { + @Override + public void run() { + try { + DrmAdapter drmAdapter = DrmAdapter.getDrmAdapter(drmParams.getScheme(), context, localDataStore); + String licenseUri = drmParams.getLicenseUri(); + + boolean isRegistered = drmAdapter.registerAsset(localAssetPath, assetId, licenseUri, listener); + if (isRegistered) { + localDataStore.save(buildAssetKey(assetId), buildMediaFormatValueAsByteArray(mediaFormat, drmParams.getScheme())); } - break; - case WidevineClassic: - if (MediaSupport.widevineClassic()) { - return params; + } catch (final IOException e) { + log.e("Error", e); + if (listener != null) { + mainHandler.post(new Runnable() { + @Override + public void run() { + listener.onFailed(localAssetPath, e); + } + }); } - break; - case PlayReadyCENC: - log.d("Skipping unsupported PlayReady params"); - break; + } } - } - return null; + }); + } + + /** + * Will register clear asset and store {@link PKMediaFormat} in local storage. + * + * @param localAssetPath - the local asset path of the asset. + * @param assetId - the asset id. + * @param mediaFormat - the media format converted to byte[]. + * @param listener - notify about the success/fail after the completion of the registration process. + */ + private void registerClearAsset(String localAssetPath, String assetId, PKMediaFormat mediaFormat, AssetRegistrationListener listener) { + localDataStore.save(buildAssetKey(assetId), buildMediaFormatValueAsByteArray(mediaFormat, null)); + listener.onRegistered(localAssetPath); } - - /** * Unregister asset. If the asset have drm protection it will be removed from {@link LocalDataStore} + * In any case the {@link PKMediaFormat} will be removed from {@link LocalDataStore} + * * @param localAssetPath - the url of the locally stored asset. - * @param assetId - the asset id - * @param listener - notify when the asset is removed. + * @param assetId - the asset id + * @param listener - notify when the asset is removed. */ public void unregisterAsset(@NonNull final String localAssetPath, - @NonNull final String assetId, final AssetRemovalListener listener) { + @NonNull final String assetId, final AssetRemovalListener listener) { + + + PKDrmParams.Scheme scheme = getLocalAssetScheme(assetId); + + if (scheme == null) { + removeAsset(localAssetPath, assetId, listener); + return; + } - PKDrmParams.Scheme scheme = guessLocalAssetScheme(localAssetPath); final DrmAdapter drmAdapter = DrmAdapter.getDrmAdapter(scheme, context, localDataStore); doInBackground(new Runnable() { @@ -176,7 +201,7 @@ public void onRemoved(final String localAssetPath) { mainHandler.post(new Runnable() { @Override public void run() { - listener.onRemoved(localAssetPath); + removeAsset(localAssetPath, assetId, listener); } }); } @@ -185,32 +210,32 @@ public void run() { }); } - @Nullable - private PKDrmParams.Scheme guessLocalAssetScheme(@NonNull String localAssetPath) { - PKMediaFormat format = PKMediaFormat.valueOfUrl(localAssetPath); - if (format == null) { - return null; - } - switch (format) { - case dash: - return PKDrmParams.Scheme.WidevineCENC; - case wvm: - return PKDrmParams.Scheme.WidevineClassic; - default: - return null; - } + private void removeAsset(String localAssetPath, String assetId, AssetRemovalListener listener) { + localDataStore.remove(buildAssetKey(assetId)); + listener.onRemoved(localAssetPath); } + /** * Check the status of the desired asset. + * * @param localAssetPath - the url of the locally stored asset. - * @param assetId - the asset id. - * @param listener - will pass the result of the status. + * @param assetId - the asset id. + * @param listener - will pass the result of the status. */ public void checkAssetStatus(@NonNull final String localAssetPath, @NonNull final String assetId, - @Nullable final AssetStatusListener listener) { + @Nullable final AssetStatusListener listener) { + + PKDrmParams.Scheme scheme = getLocalAssetScheme(assetId); + if (scheme == null) { + checkClearAssetStatus(localAssetPath, assetId, listener); + } else { + checkDrmAssetStatus(localAssetPath, assetId, scheme, listener); + } + } + + private void checkDrmAssetStatus(final String localAssetPath, final String assetId, PKDrmParams.Scheme scheme, final AssetStatusListener listener) { - PKDrmParams.Scheme scheme = guessLocalAssetScheme(localAssetPath); final DrmAdapter drmAdapter = DrmAdapter.getDrmAdapter(scheme, context, localDataStore); doInBackground(new Runnable() { @@ -233,9 +258,60 @@ public void run() { }); } + private void checkClearAssetStatus(String localAssetPath, String assetId, AssetStatusListener listener) { + try { + localDataStore.load(buildAssetKey(assetId)); + listener.onStatus(localAssetPath, 0, 0, true); + } catch (FileNotFoundException e) { + listener.onStatus(localAssetPath, 0, 0, false); + } + } + + private static PKDrmParams findSupportedDrmParams(@NonNull PKMediaSource mediaSource) { + if (mediaSource.getDrmData() == null) { + return null; + } + + for (PKDrmParams params : mediaSource.getDrmData()) { + switch (params.getScheme()) { + case WidevineCENC: + if (MediaSupport.widevineModular()) { + return params; + } + break; + case WidevineClassic: + if (MediaSupport.widevineClassic()) { + return params; + } + break; + case PlayReadyCENC: + log.d("Skipping unsupported PlayReady params"); + break; + } + } + return null; + } + + @Nullable + private PKDrmParams.Scheme getLocalAssetScheme(@NonNull String assetId) { + try { + String mediaFormatValue = new String(localDataStore.load(buildAssetKey(assetId))); + String[] splitFormatValue = mediaFormatValue.split(":"); + String schemeName = splitFormatValue[1]; + if(schemeName.equals("null")) { + return null; + } + + return PKDrmParams.Scheme.valueOf(schemeName); + + } catch (FileNotFoundException e) { + log.e(e.getMessage()); + return null; + } + } + /** - * - * @param assetId - the id of the asset. + * @param assetId - the id of the asset. * @param localAssetPath - the actual url of the video that should be played. * @return - the {@link PKMediaSource} that should be passed to the player. */ @@ -243,8 +319,22 @@ public PKMediaSource getLocalMediaSource(@NonNull final String assetId, @NonNull return new LocalMediaSource(localDataStore, localAssetPath, assetId); } + /** + * Will check if passed parameters are valid. + * + * @param url - url of the media. + * @param localAssetPath - the local asset path of the media. + * @param assetId - the asset id. + */ + private void checkIfParamsAreValid(String url, String localAssetPath, String assetId) { + checkNotEmpty(url, "mediaSource.url"); + checkNotEmpty(localAssetPath, "localAssetPath"); + checkNotEmpty(assetId, "assetId"); + } + /** * Checking arguments. if the argument is not valid, will throw an {@link IllegalArgumentException} + * * @param invalid - the state of the argument. * @param message - message to print, to the console. */ @@ -256,7 +346,8 @@ private void checkArg(boolean invalid, String message) { /** * check the passed String. - * @param obj - String to check. + * + * @param obj - String to check. * @param name - the descriptive name of the String. */ private void checkNotEmpty(String obj, String name) { @@ -269,6 +360,7 @@ private void doInBackground(Runnable runnable) { /** * Check if network connection is available. + * * @param context - context. * @return - true if there is network connection, otherwise - false. */ @@ -278,6 +370,22 @@ private boolean isOnline(Context context) { return !(netInfo == null || !netInfo.isConnected() || !netInfo.isAvailable()); } + private String buildAssetKey(String assetId) { + return ASSET_ID_PREFIX + assetId; + } + + private byte[] buildMediaFormatValueAsByteArray(PKMediaFormat mediaFormat, PKDrmParams.Scheme scheme) { + String mediaFormatName = mediaFormat.toString(); + String schemeName = "null"; + if(scheme != null) { + schemeName = scheme.toString(); + } + String stringBuilder = mediaFormatName + + ":" + + schemeName; + return stringBuilder.getBytes(); + } + /** * The local media source that should be passed to the player * when offline(locally stored) media want to be played. @@ -289,8 +397,8 @@ public static class LocalMediaSource extends PKMediaSource { /** * @param localDataStore - the storage from where drm keySetId is stored. - * @param localPath - the local url of the media. - * @param assetId - the id of the media. + * @param localPath - the local url of the media. + * @param assetId - the id of the media. */ LocalMediaSource(LocalDataStore localDataStore, String localPath, String assetId) { setId(assetId); @@ -317,11 +425,11 @@ public static class DefaultLocalDataStore implements LocalDataStore { private final PKLog log = PKLog.get("DefaultLocalDataStore"); - private static final String LOCAL_DRM_SHARED_PREFERENCE_STORAGE = "PlayKitLocalDrmStorage"; + private static final String LOCAL_SHARED_PREFERENCE_STORAGE = "PlayKitLocalStorage"; private final SharedPreferences sharedPreferences; - public DefaultLocalDataStore(Context context){ - sharedPreferences = context.getSharedPreferences(LOCAL_DRM_SHARED_PREFERENCE_STORAGE, 0); + public DefaultLocalDataStore(Context context) { + sharedPreferences = context.getSharedPreferences(LOCAL_SHARED_PREFERENCE_STORAGE, 0); } @Override diff --git a/playkit/src/main/java/com/kaltura/playkit/PKPluginConfigs.java b/playkit/src/main/java/com/kaltura/playkit/PKPluginConfigs.java index 664e8d7c5..fc11d6341 100644 --- a/playkit/src/main/java/com/kaltura/playkit/PKPluginConfigs.java +++ b/playkit/src/main/java/com/kaltura/playkit/PKPluginConfigs.java @@ -1,13 +1,13 @@ package com.kaltura.playkit; -import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; /** * Created by Noam Tamim @ Kaltura on 22/02/2017. */ -public class PKPluginConfigs { +public class PKPluginConfigs implements Iterable> { private Map configs = new HashMap<>(); @@ -19,7 +19,7 @@ public void setPluginConfig(String pluginName, Object settings) { this.configs.put(pluginName, settings); } - public Map getPluginConfigsMap() { - return Collections.unmodifiableMap(configs); + public Iterator> iterator() { + return configs.entrySet().iterator(); } } diff --git a/playkit/src/main/java/com/kaltura/playkit/PlayKitManager.java b/playkit/src/main/java/com/kaltura/playkit/PlayKitManager.java index 0822fa041..7a13c46d9 100644 --- a/playkit/src/main/java/com/kaltura/playkit/PlayKitManager.java +++ b/playkit/src/main/java/com/kaltura/playkit/PlayKitManager.java @@ -1,6 +1,7 @@ package com.kaltura.playkit; import android.content.Context; +import android.support.annotation.Nullable; import com.kaltura.playkit.player.MediaSupport; @@ -37,24 +38,12 @@ static PKPlugin createPlugin(String name) { return pluginFactory == null ? null : pluginFactory.newInstance(); } - /** - * @deprecated Use {@link #loadPlayer(PKPluginConfigs, Context)}. The {@link PlayerConfig#media} - * field is ignored when loading the player. - * @param playerConfig - * @param context - * @return - */ - @Deprecated - public static Player loadPlayer(PlayerConfig playerConfig, Context context) { - return loadPlayer(playerConfig.plugins, context); - } - - public static Player loadPlayer(PKPluginConfigs pluginConfigs, Context context) { - + public static Player loadPlayer(Context context, @Nullable PKPluginConfigs pluginConfigs) { + MediaSupport.initialize(context); PlayerLoader playerLoader = new PlayerLoader(context); - playerLoader.load(pluginConfigs); + playerLoader.load(pluginConfigs != null ? pluginConfigs : new PKPluginConfigs()); return playerLoader; } } diff --git a/playkit/src/main/java/com/kaltura/playkit/PlayerConfig.java b/playkit/src/main/java/com/kaltura/playkit/PlayerConfig.java deleted file mode 100644 index 2cf0fbf88..000000000 --- a/playkit/src/main/java/com/kaltura/playkit/PlayerConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.kaltura.playkit; - -/** - * Player configuration data holder. - * This object is used by the player in order to preset desired configurations. - * Created by Noam Tamim @ Kaltura on 18/09/2016. - * @deprecated PlayerConfig.Media and PlayerConfig.Plugins are now {@link PKMediaConfig} and - * {@link PKPluginConfigs}, respectively. This class remains to ease the migration, and will be removed. - */ -@Deprecated -public class PlayerConfig { - - public final PKMediaConfig media = new PKMediaConfig(); - public final PKPluginConfigs plugins = new PKPluginConfigs(); - -} diff --git a/playkit/src/main/java/com/kaltura/playkit/PlayerLoader.java b/playkit/src/main/java/com/kaltura/playkit/PlayerLoader.java index e01e17374..fdf45399c 100644 --- a/playkit/src/main/java/com/kaltura/playkit/PlayerLoader.java +++ b/playkit/src/main/java/com/kaltura/playkit/PlayerLoader.java @@ -51,7 +51,7 @@ public void onEvent(PKEvent event) { Player player = playerController; - for (Map.Entry entry : pluginsConfig.getPluginConfigsMap().entrySet()) { + for (Map.Entry entry : pluginsConfig) { String name = entry.getKey(); PKPlugin plugin = loadPlugin(name, player, entry.getValue(), messageBus, context); diff --git a/playkit/src/main/java/com/kaltura/playkit/player/PlayerController.java b/playkit/src/main/java/com/kaltura/playkit/player/PlayerController.java index be01b023b..b6950f477 100644 --- a/playkit/src/main/java/com/kaltura/playkit/player/PlayerController.java +++ b/playkit/src/main/java/com/kaltura/playkit/player/PlayerController.java @@ -31,7 +31,7 @@ public class PlayerController implements Player { private static final int ALLOWED_ERROR_RETRIES = 3; - private PlayerEngine player; + private PlayerEngine player = null; private Context context; private PlayerView rootPlayerView; @@ -111,6 +111,10 @@ public void onStateChanged(PlayerState oldState, PlayerState newState) { public PlayerController(Context context) { this.context = context; + initializeRootPlayerView(); + } + + private void initializeRootPlayerView() { this.rootPlayerView = new PlayerView(context) { @Override public void hideVideoSurface() { @@ -150,8 +154,10 @@ private void setVideoSurfaceVisibility(boolean isVisible) { } public void prepare(@NonNull PKMediaConfig mediaConfig) { + isNewEntry = isNewEntry(mediaConfig); this.mediaConfig = mediaConfig; + PKMediaSource source = SourceSelector.selectSource(mediaConfig.getMediaEntry()); if (source == null) { @@ -159,24 +165,46 @@ public void prepare(@NonNull PKMediaConfig mediaConfig) { return; } - if (source.getMediaFormat() != PKMediaFormat.wvm) { - if (player == null) { - player = new ExoPlayerWrapper(context); - togglePlayerListeners(true); - } - } else { - if (player == null) { - player = new MediaPlayerWrapper(context); - togglePlayerListeners(true); - } - } - if (playerEngineView == null) { - playerEngineView = player.getView(); - rootPlayerView.addView(playerEngineView); + boolean shouldSwitchBetweenPlayers = shouldSwitchBetweenPlayers(source); + + if (shouldSwitchBetweenPlayers || player == null) { //if player is null consider it as switch player flow. + switchPlayers(source.getMediaFormat()); } + player.load(source); } + private void switchPlayers(PKMediaFormat mediaFormat) { + removeAllViews(); + + if (player != null) { + player.destroy(); + } + initializePlayer(mediaFormat); + + addPlayerView(); + } + + + private void initializePlayer(PKMediaFormat mediaFormat) { + //Decide which player wrapper should be initialized. + if (mediaFormat != PKMediaFormat.wvm) { + player = new ExoPlayerWrapper(context); + togglePlayerListeners(true); + } else { + player = new MediaPlayerWrapper(context); + togglePlayerListeners(true); + } + } + + private void addPlayerView() { + if (playerEngineView != null) { + return; + } + + playerEngineView = player.getView(); + rootPlayerView.addView(playerEngineView); + } @Override public void destroy() { @@ -287,6 +315,9 @@ public boolean isPlaying() { } private void togglePlayerListeners(boolean enable) { + if (player == null) { + return; + } if (enable) { player.setEventListener(eventTrigger); player.setStateChangedListener(stateChangedTrigger); @@ -359,13 +390,33 @@ private boolean isNewEntry(PKMediaConfig mediaConfig) { } String oldEntryId = this.mediaConfig.getMediaEntry().getId(); - if(oldEntryId == null){ + if (oldEntryId == null) { return true; } String newEntryId = mediaConfig.getMediaEntry().getId(); return !oldEntryId.equals(newEntryId); } + private boolean shouldSwitchBetweenPlayers(PKMediaSource newSource) { + + PKMediaFormat currentMediaFormat = newSource.getMediaFormat(); + if (currentMediaFormat != PKMediaFormat.wvm && player instanceof MediaPlayerWrapper) { + return true; + } + + if (currentMediaFormat == PKMediaFormat.wvm && player instanceof ExoPlayerWrapper) { + return true; + } + + return false; + } + + private void removeAllViews() { + togglePlayerListeners(false); + rootPlayerView.removeAllViews(); + playerEngineView = null; + } + private boolean maybeHandleExceptionLocally(PlayerEvent.ExceptionInfo exceptionInfo) { if (exceptionInfo.getErrorCounter() > ALLOWED_ERROR_RETRIES) { log.w("Amount of the retries that happened on the same error are exceed the allowed amount of retries. Allowed amount of retries " + ALLOWED_ERROR_RETRIES + " actual amount " + exceptionInfo.getErrorCounter()); diff --git a/playkitdemo/src/main/java/com/kaltura/playkitdemo/MainActivity.java b/playkitdemo/src/main/java/com/kaltura/playkitdemo/MainActivity.java index 1a2e89309..4b21d0ada 100644 --- a/playkitdemo/src/main/java/com/kaltura/playkitdemo/MainActivity.java +++ b/playkitdemo/src/main/java/com/kaltura/playkitdemo/MainActivity.java @@ -210,7 +210,7 @@ private void onMediaLoaded(PKMediaEntry mediaEntry) { configurePlugins(pluginConfig); - player = PlayKitManager.loadPlayer(pluginConfig, this); + player = PlayKitManager.loadPlayer(this, pluginConfig); log.d("Player: " + player.getClass()); addPlayerListeners(progressBar);