Skip to content

Commit

Permalink
feat: initial android implemenation with ExoPlayer
Browse files Browse the repository at this point in the history
  • Loading branch information
Arnaud de Mouhy committed Sep 22, 2020
1 parent 1f82b7c commit 32b4d25
Show file tree
Hide file tree
Showing 11 changed files with 478 additions and 25 deletions.
5 changes: 3 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ android {
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
versionCode 1
versionName "1.0"

}

buildTypes {
release {
minifyEnabled false
Expand Down Expand Up @@ -127,4 +127,5 @@ dependencies {
// noinspection GradleDynamicVersion
api 'com.facebook.react:react-native:+'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "com.google.android.exoplayer:exoplayer:2.12.0"
}
181 changes: 181 additions & 0 deletions android/reactnativeradioplayer.iml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.reactnativeradioplayer">

<uses-permission android:name="android.permission.WAKE_LOCK" />
</manifest>
116 changes: 104 additions & 12 deletions android/src/main/java/com/reactnativeradioplayer/RadioPlayerModule.kt
Original file line number Diff line number Diff line change
@@ -1,24 +1,116 @@
package com.reactnativeradioplayer

import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.Promise
import android.util.Log
import com.facebook.react.bridge.*
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
import com.google.android.exoplayer2.C.WAKE_MODE_NETWORK
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.metadata.Metadata
import com.google.android.exoplayer2.metadata.MetadataOutput
import com.google.android.exoplayer2.metadata.icy.IcyInfo
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.util.EventLogger

class RadioPlayerModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {

class RadioPlayerModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext), Player.EventListener, MetadataOutput {

private val context = reactContext
private var player: SimpleExoPlayer = SimpleExoPlayer.Builder(reactContext).build()

override fun getName(): String {
return "RadioPlayer"
}

// Example method
// See https://facebook.github.io/react-native/docs/native-modules-android
init {
UiThreadUtil.runOnUiThread {
player.addAnalyticsListener(EventLogger(DefaultTrackSelector(this.context)))
player.addMetadataOutput(this)
player.setThrowsWhenUsingWrongThread(true)
player.setWakeMode(WAKE_MODE_NETWORK)
player.addListener(this)
}
}

@ReactMethod
fun multiply(a: Int, b: Int, promise: Promise) {

promise.resolve(a * b)

fun radioURL(uri: String) {
UiThreadUtil.runOnUiThread {
val item: MediaItem = MediaItem.fromUri(uri)
player.setMediaItem(item)
player.prepare()
player.play()
//play()
}
}


@ReactMethod
fun play() {
UiThreadUtil.runOnUiThread {
if (player.isPlaying) {
player.stop()
}
player.prepare()
player.play()
}
}

@ReactMethod
fun stop() {
UiThreadUtil.runOnUiThread { player.stop() }
}

override fun onPlaybackStateChanged(state: Int) {
var stateString = "unknown"
var playbackStateString = "unknown"
when (state) {
Player.STATE_IDLE, Player.STATE_ENDED -> {
stateString = "loadingFinished"
playbackStateString = "stopped"
}
Player.STATE_BUFFERING -> {
stateString = "loading"
playbackStateString = "paused"
}
Player.STATE_READY -> {
stateString = "loadingFinished"
playbackStateString = "playing"
}
}
val stateMap = WritableNativeMap()
stateMap.putString("state", stateString)
sendEvent(this.context, "StateDidChange", stateMap)

val playbackStateMap = WritableNativeMap()
playbackStateMap.putString("playbackState", playbackStateString)
sendEvent(this.context, "PlaybackStateDidChange", playbackStateMap)
}

private fun sendEvent(reactContext: ReactContext,
eventName: String,
params: NativeMap) {
reactContext
.getJSModule(RCTDeviceEventEmitter::class.java)
.emit(eventName, params)
}

override fun onMetadata(metadata: Metadata) {
Log.i("RadioPlayerMetadata", metadata.toString())
var artistName = "Unknown"
var trackName = "Unknown"
for (i in 1..metadata.length()) {
val entry: Metadata.Entry = metadata.get(i-1)
if (entry is IcyInfo) {
if (entry.title != null) {
val parts: List<String> = entry.title!!.split(" - ")
artistName = parts[0]
trackName = parts[1]
}
}
}
val metadataMap = WritableNativeMap()
metadataMap.putString("artistName", artistName)
metadataMap.putString("trackName", trackName)
sendEvent(this.context, "MetadataDidChange", metadataMap)
}
}
19 changes: 19 additions & 0 deletions example/android/RadioPlayerExample.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="RadioPlayerExample" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
147 changes: 147 additions & 0 deletions example/android/app/app.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.5.2" />
<option name="LAST_KNOWN_AGP_VERSION" value="3.5.2" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/build/generated/res/resValues/debug" />
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/classes" />
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debug/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debug/compileDebugRenderscript/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/react/debug" type="java-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debugAndroidTest/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debugAndroidTest/compileDebugAndroidTestAidl/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debugAndroidTest/compileDebugAndroidTestRenderscript/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/ap_generated_sources/debugUnitTest/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/rncli/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="TEST" name="Gradle: androidx.multidex:multidex-instrumentation:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.soloader:nativeloader:0.8.2@jar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.infer.annotation:infer-annotation:0.11.2@jar" level="project" />
<orderEntry type="library" name="Gradle: com.google.code.findbugs:jsr305:3.0.2@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.collection:collection:1.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.arch.core:core-common:2.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.annotation:annotation:1.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp-urlconnection:3.12.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp:3.14.1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okio:okio:1.17.2@jar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.yoga:proguard-annotations:1.14.1@jar" level="project" />
<orderEntry type="library" name="Gradle: javax.inject:javax.inject:1@jar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fbjni:fbjni-java-only:0.0.3@jar" level="project" />
<orderEntry type="library" name="Gradle: androidx.multidex:multidex:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.flipper:flipper:0.33.1@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.react:react-native:0.62.2@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.soloader:soloader:0.8.2@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.soloader:annotation:0.8.2@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.swiperefreshlayout:swiperefreshlayout:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat-resources:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.drawerlayout:drawerlayout:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.viewpager:viewpager:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.activity:activity:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable-animated:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.customview:customview:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.core:core:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.interpolator:interpolator:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.cursoradapter:cursoradapter:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable:1.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.savedstate:savedstate:1.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.flipper:flipper-network-plugin:0.33.1@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline-okhttp3:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.flipper:flipper-fresco-plugin:0.33.1@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:fresco:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:fbcore:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:drawee:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline-base:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:nativeimagefilters:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.facebook.fresco:nativeimagetranscoder:2.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: org.webkit:android-jsc:r245459@aar" level="project" />
<orderEntry type="module" module-name="reactnativeradioplayer" />
</component>
</module>
3 changes: 3 additions & 0 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ android {
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
multiDexEnabled true
}
splits {
abi {
Expand Down Expand Up @@ -210,6 +211,8 @@ dependencies {
}

implementation project(':reactnativeradioplayer')
implementation 'com.android.support:multidex:1.0.3'

}

// Run this once to be able to run the application with BUCK
Expand Down
1 change: 1 addition & 0 deletions example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package="com.example.reactnativeradioplayer">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

<application
android:name=".MainApplication"
Expand Down
Loading

0 comments on commit 32b4d25

Please sign in to comment.