Skip to content
This repository has been archived by the owner on Jan 17, 2023. It is now read-only.

Commit

Permalink
Merge branch 'release/0.10.6'
Browse files Browse the repository at this point in the history
  • Loading branch information
Video Players committed Dec 3, 2018
2 parents 5b22fe9 + fd0af4f commit e9ff317
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 51 deletions.
2 changes: 1 addition & 1 deletion clappr/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ apply plugin: 'org.jetbrains.dokka-android'
apply from: 'versioning.gradle'

group = 'io.clappr.player'
version = '0.10.5'
version = '0.10.6'

def publishAttrs = buildPublishAttrs(version)

Expand Down
28 changes: 18 additions & 10 deletions clappr/src/main/kotlin/io/clappr/player/plugin/Loader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import kotlin.reflect.full.primaryConstructor

class Loader(extraPlugins: List<KClass<out Plugin>> = emptyList(), extraPlaybacks: List<KClass<out Playback>> = emptyList()) {
companion object {
@JvmStatic val registeredPlugins = mutableMapOf<String, KClass<out Plugin>>()
@JvmStatic private val registeredPlugins = mutableMapOf<String, KClass<out Plugin>>()
@JvmStatic private val registeredPlaybacks= mutableListOf<KClass<out Playback>>()

@JvmStatic
Expand All @@ -29,13 +29,21 @@ class Loader(extraPlugins: List<KClass<out Plugin>> = emptyList(), extraPlayback
val pluginName = (pluginClass.companionObjectInstance as? NamedType)?.name
pluginName?.let {
if (pluginName.isNotEmpty()) {
registeredPlugins.put(pluginName, pluginClass)
registeredPlugins[pluginName] = pluginClass
return true
}
}
return false
}

@JvmStatic
fun unregisterPlugin(pluginClass: KClass<out Plugin>) =
(pluginClass.companionObjectInstance as? NamedType)?.run {
name?.takeIf { it.isNotEmpty() && registeredPlugins.containsKey(it) }?.let {
registeredPlugins.remove(it) != null
}
} ?: false

@JvmStatic
fun registerPlayback(playbackClass: KClass<out Playback>): Boolean {
val playbackName = (playbackClass.companionObjectInstance as? NamedType)?.name
Expand Down Expand Up @@ -63,9 +71,9 @@ class Loader(extraPlugins: List<KClass<out Plugin>> = emptyList(), extraPlayback

private val externalPlaybacks = mutableListOf<KClass<out Playback>>()

val availablePlugins = mutableMapOf<String, KClass<out Plugin>>()
private val availablePlugins = mutableMapOf<String, KClass<out Plugin>>()

val availablePlaybacks = mutableListOf<KClass<out Playback>>()
private val availablePlaybacks = mutableListOf<KClass<out Playback>>()

init {
for (pluginClass in registeredPlugins.values) {
Expand Down Expand Up @@ -98,12 +106,13 @@ class Loader(extraPlugins: List<KClass<out Plugin>> = emptyList(), extraPlayback

fun loadPlayback(source: String, mimeType: String? = null, options: Options): Playback? {
var playback: Playback? = null

try {
val playbackClass = registeredPlaybacks.first { supportsSource(it, source, mimeType) }
val constructor = playbackClass.primaryConstructor
playback = constructor?.call(source, mimeType, options) as? Playback
} catch (e: Exception) {
}
} catch (e: Exception) { }

return playback
}

Expand All @@ -120,19 +129,18 @@ class Loader(extraPlugins: List<KClass<out Plugin>> = emptyList(), extraPlayback
val name : String? = (pluginClass.companionObjectInstance as? NamedType)?.name
name?.let {
if (name.isNotEmpty()) {
availablePlugins.put(name, pluginClass)
availablePlugins[name] = pluginClass
}
}
}

private fun loadPlugin(component: BaseObject, pluginClass: KClass<out Plugin>) : Plugin? {
var plugin: Plugin? = null

val constructor = pluginClass.primaryConstructor

try {
plugin = constructor?.call(component) as? Plugin
} catch (e: Exception) {
}
} catch (e: Exception) { }

return plugin
}
Expand Down
135 changes: 108 additions & 27 deletions clappr/src/test/kotlin/io/clappr/player/plugin/LoaderTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package io.clappr.player.plugin

import io.clappr.player.BuildConfig
import io.clappr.player.base.BaseObject
import io.clappr.player.base.ContainerTest
import io.clappr.player.base.NamedType
import io.clappr.player.base.Options
import io.clappr.player.components.Container
import io.clappr.player.components.Core
import io.clappr.player.components.Playback
import io.clappr.player.components.PlaybackSupportInterface
Expand All @@ -20,22 +20,21 @@ import org.robolectric.shadows.ShadowApplication
import kotlin.reflect.KClass

@RunWith(RobolectricTestRunner::class)
@Config(constants = BuildConfig::class, sdk = intArrayOf(23))
@Config(constants = BuildConfig::class, sdk = [23])
class LoaderTest {
class TestPlugin : Plugin(BaseObject()) {
class TestPlugin(baseObject: BaseObject) : Plugin(baseObject) {
companion object: NamedType {
override val name = "testplugin"
}
}

class SameNameTestPlugin : Plugin(BaseObject()) {
class SameNameTestPlugin(baseObject: BaseObject) : Plugin(baseObject) {
companion object: NamedType {
override val name = "testplugin"
}
}

class NoNameTestPlugin : Plugin(BaseObject()) {
}
class NoNameTestPlugin(baseObject: BaseObject) : Plugin(baseObject)

class TestCorePlugin(core: Core) : CorePlugin(core) {
companion object: NamedType {
Expand Down Expand Up @@ -74,120 +73,202 @@ class LoaderTest {
@Before
fun setup() {
BaseObject.context = ShadowApplication.getInstance().applicationContext

Loader.clearPlaybacks()
Loader.clearPlugins()
}

@Test
fun shouldHaveAnEmptyInitialPluginList() {
val expectedListSize = 0

val loader = Loader()
assertTrue("default plugins should be empty", loader.availablePlugins.isEmpty())
val corePlugins = loader.loadPlugins(Core(loader, Options()))
val containerPlugins = loader.loadPlugins(Container(loader, Options()))

assertEquals(expectedListSize, corePlugins.size)
assertEquals(expectedListSize, containerPlugins.size)
}

@Test
fun shouldAllowRegisteringPlugins() {
val expectedLoadedPluginsListSize = 1
val expectedLoadedPluginName = "coreplugin"

Loader.registerPlugin(TestCorePlugin::class)

val loader = Loader()
assertTrue("no plugin have been registered", loader.availablePlugins.isNotEmpty())
val loadedPlugins = loader.loadPlugins(Core(loader, Options()))

assertEquals(expectedLoadedPluginsListSize, loadedPlugins.size)
assertEquals(expectedLoadedPluginName, loadedPlugins[0].name)
}

@Test
fun shouldAddExternalPlugins() {
fun shouldAllowUnregisteringPlugins() {
val expectedLoadedPluginsListSize = 0

Loader.registerPlugin(TestCorePlugin::class)
val didUnregistered = Loader.unregisterPlugin(TestCorePlugin::class)

val loader = Loader()
val externalPlugins = listOf<KClass<out Plugin>>(TestPlugin::class)
val loaderExternal = Loader(externalPlugins)
assertTrue("no external plugin have been added", (loaderExternal.availablePlugins.size - loader.availablePlugins.size) == 1)
val loadedPlugins = loader.loadPlugins(Core(loader, Options()))

assertTrue("plugin still registered", didUnregistered)
assertEquals(expectedLoadedPluginsListSize, loadedPlugins.size)
}

@Test
fun shouldNotUnregisterNotRegisteredPlugin() {
val didUnregistered = Loader.unregisterPlugin(TestPlugin::class)

assertFalse("plugin should not be unregistered", didUnregistered)
}

@Test
fun shouldAddExternalPlugins() {
val expectedLoadedPluginsListSize = 1
val expectedLoadedPluginName = "testplugin"

val loaderExternal = Loader(listOf<KClass<out Plugin>>(TestPlugin::class))
val loadedPlugins = loaderExternal.loadPlugins(BaseObject())

assertEquals(expectedLoadedPluginsListSize, loadedPlugins.size)
assertEquals(expectedLoadedPluginName, loadedPlugins[0].name)
}

@Test
fun shouldDisregardExternalPluginsWithoutName() {
val loader = Loader()
val expectedLoadedPluginsListSize = 0
val externalPlugins = listOf<KClass<out Plugin>>(NoNameTestPlugin::class)

val loaderExternal = Loader(externalPlugins)
assertTrue("nameless external plugin added", loaderExternal.availablePlugins.size == loader.availablePlugins.size)
val loadedPlugins = loaderExternal.loadPlugins(BaseObject())

assertEquals(expectedLoadedPluginsListSize, loadedPlugins.size)
}

@Test
fun externalPluginShouldReplaceDefaultPlugin() {
val expectedLoadedPluginsListSize = 1
val expectedLoadedPluginName = "coreplugin"

Loader.registerPlugin(CorePlugin::class)

val loader = Loader()
assertNotNull("no default coreplugin: ${loader.availablePlugins}", loader.availablePlugins["coreplugin"])
val externalPlugins = listOf<KClass<out Plugin>>(TestCorePlugin::class)
val loaderExternal = Loader(externalPlugins)
assertFalse("no external plugin replace", loader.availablePlugins["coreplugin"] == loaderExternal.availablePlugins["coreplugin"])
assertTrue("invalid external plugin", TestCorePlugin::class == loaderExternal.availablePlugins["coreplugin"])
val loadedPlugins = loader.loadPlugins(Core(loader, Options()))

assertEquals(expectedLoadedPluginsListSize, loadedPlugins.size)
assertEquals(expectedLoadedPluginName, loadedPlugins[0].name)

val loaderExternal = Loader(listOf<KClass<out Plugin>>(TestCorePlugin::class))
val loadedExternalPlugins = loaderExternal.loadPlugins(Core(loaderExternal, Options()))

assertEquals(expectedLoadedPluginsListSize, loadedExternalPlugins.size)
assertEquals(expectedLoadedPluginName, loadedExternalPlugins[0].name)
assertTrue("invalid external plugin", TestCorePlugin::class == loadedExternalPlugins[0]::class)
}

@Test
fun shouldOverwritePluginWithDuplicateNames() {
val expectedLoadedPluginsListSize = 1
val expectedLoadedPluginName = "testplugin"

Loader.registerPlugin(TestPlugin::class)
Loader.registerPlugin(SameNameTestPlugin::class)

val loader = Loader()
assertTrue("should not have duplicate plugins", loader.availablePlugins.size == 1)
val loadedPlugins = loader.loadPlugins(BaseObject())

assertEquals(expectedLoadedPluginsListSize, loadedPlugins.size)
assertEquals(expectedLoadedPluginName, loadedPlugins[0].name)
}

@Test
fun shouldHaveAnEmptyInitialPlaybackList() {
val loader = Loader()
assertTrue("default playbacks should be empty", loader.availablePlaybacks.isEmpty())

val loadedDashPlayback = loader.loadPlayback("123.mpd", "video", Options())
val loadedHLSPlayback = loader.loadPlayback("123.m3u8", "video", Options())
val loadedMP4Playback = loader.loadPlayback("123.mp4", "video", Options())

assertNull("no playback should be loaded", loadedDashPlayback)
assertNull("no playback should be loaded", loadedHLSPlayback)
assertNull("no playback should be loaded", loadedMP4Playback)
}

@Test
fun shouldAllowRegisteringPlaybacks() {
Loader.registerPlayback(TestPlaybackMp4::class)

val loader = Loader()
assertTrue("default playbacks should not be empty", loader.availablePlaybacks.isNotEmpty())
val loadedMP4Playback = loader.loadPlayback("123.mp4", "video", Options())

assertNotNull("mp4 playback should not be empty", loadedMP4Playback)
}

@Test
fun shouldOverwritePlaybacksWithDuplicateNames() {
Loader.registerPlayback(TestPlaybackMp4::class)
Loader.registerPlayback(TestDuplicatePlayback::class)

val loader = Loader()
assertTrue("should not have duplicate playbacks", loader.availablePlaybacks.size == 1)
val loadedPlayback = loader.loadPlayback("123.mp4", "video", Options())

assertNotNull("playback should not be empty", loadedPlayback)
assertEquals(TestDuplicatePlayback::class, loadedPlayback!!::class)
}

@Test
fun shouldInstantiatePlayback() {
Loader.registerPlayback(TestPlaybackAny::class)

val loader = Loader()
val playback = loader.loadPlayback("some-source.mp4", null, Options())

assertNotNull("should have loaded playback", playback)
}

@Test
fun shouldInstantiatePlaybackWhichCanPlaySource() {
Loader.registerPlayback(TestPlaybackMp4::class)
Loader.registerPlayback(TestPlaybackDash::class)

val loader = Loader()
var playback = loader.loadPlayback("some-source.mp4", null, Options())

assertNotNull("should have loaded playback", playback)
assertTrue("should load mp4 playback", playback is TestPlaybackMp4)

playback = loader.loadPlayback("some-source.mpd", null, Options())

assertNotNull("should have loaded playback", playback)
assertTrue("should load dash playback", playback is TestPlaybackDash)
}

@Test
fun shouldInstantiateFirstPlaybackInRegisteredListWhenThereAreMoreThanOneThatCanPlaySource() {
Loader.registerPlayback(NoOpPlayback::class)
var loader = Loader()

val loader = Loader()
var playback = loader.loadPlayback("some-source.mp4", null, Options())

assertNotNull("should have loaded playback", playback)
assertTrue("should load no-op playback", playback is NoOpPlayback)

Loader.registerPlayback(TestPlaybackMp4::class)
loader = loader

playback = loader.loadPlayback("some-source.mp4", null, Options())

assertNotNull("should have loaded playback", playback)
assertTrue("should load mp4 playback", playback is TestPlaybackMp4)
}

@Test
fun shouldReturnNullForNoPlayback() {
var loader = Loader()
var playback = loader.loadPlayback("some-source.mp4", null, Options())
val loader = Loader()
val playback = loader.loadPlayback("some-source.mp4", null, Options())

assertNull("should not have loaded playback", playback)
}
}
14 changes: 1 addition & 13 deletions doc/clappr/io.clappr.player.plugin/-loader/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,13 @@
|---|---|
| [&lt;init&gt;](-init-.md) | `Loader(extraPlugins: `[`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)`<`[`KClass`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html)`<out `[`Plugin`](../-plugin/index.md)`>> = emptyList(), extraPlaybacks: `[`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)`<`[`KClass`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html)`<out `[`Playback`](../../io.clappr.player.components/-playback/index.md)`>> = emptyList())` |

### Properties

| Name | Summary |
|---|---|
| [availablePlaybacks](available-playbacks.md) | `val availablePlaybacks: `[`MutableList`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-list/index.html)`<`[`KClass`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html)`<out `[`Playback`](../../io.clappr.player.components/-playback/index.md)`>>` |
| [availablePlugins](available-plugins.md) | `val availablePlugins: `[`MutableMap`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-map/index.html)`<`[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, `[`KClass`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html)`<out `[`Plugin`](../-plugin/index.md)`>>` |

### Functions

| Name | Summary |
|---|---|
| [loadPlayback](load-playback.md) | `fun loadPlayback(source: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, mimeType: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`? = null, options: `[`Options`](../../io.clappr.player.base/-options/index.md)`): `[`Playback`](../../io.clappr.player.components/-playback/index.md)`?` |
| [loadPlugins](load-plugins.md) | `fun loadPlugins(context: `[`BaseObject`](../../io.clappr.player.base/-base-object/index.md)`): `[`List`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/index.html)`<`[`Plugin`](../-plugin/index.md)`>` |

### Companion Object Properties

| Name | Summary |
|---|---|
| [registeredPlugins](registered-plugins.md) | `val registeredPlugins: `[`MutableMap`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-map/index.html)`<`[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, `[`KClass`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html)`<out `[`Plugin`](../-plugin/index.md)`>>` |

### Companion Object Functions

| Name | Summary |
Expand All @@ -39,3 +26,4 @@
| [registerPlayback](register-playback.md) | `fun registerPlayback(playbackClass: `[`KClass`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html)`<out `[`Playback`](../../io.clappr.player.components/-playback/index.md)`>): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) |
| [registerPlugin](register-plugin.md) | `fun registerPlugin(pluginClass: `[`KClass`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html)`<out `[`Plugin`](../-plugin/index.md)`>): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) |
| [supportsSource](supports-source.md) | `fun supportsSource(playbackClass: `[`KClass`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html)`<out `[`Playback`](../../io.clappr.player.components/-playback/index.md)`>, source: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`, mimeType: `[`String`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/index.html)`? = null): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) |
| [unregisterPlugin](unregister-plugin.md) | `fun unregisterPlugin(pluginClass: `[`KClass`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html)`<out `[`Plugin`](../-plugin/index.md)`>): `[`Boolean`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean/index.html) |

0 comments on commit e9ff317

Please sign in to comment.