diff --git a/android/build.gradle b/android/build.gradle index ca21270..f17abde 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -33,9 +33,9 @@ android { targetSdkVersion getExtOrIntegerDefault('targetSdkVersion') versionCode 1 versionName "1.0" - + } - + buildTypes { release { minifyEnabled false @@ -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" } diff --git a/android/reactnativeradioplayer.iml b/android/reactnativeradioplayer.iml new file mode 100644 index 0000000..2b3dfb4 --- /dev/null +++ b/android/reactnativeradioplayer.iml @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index f6a9621..605dec9 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ + diff --git a/android/src/main/java/com/reactnativeradioplayer/RadioPlayerModule.kt b/android/src/main/java/com/reactnativeradioplayer/RadioPlayerModule.kt index 8bdbd75..c5964ff 100644 --- a/android/src/main/java/com/reactnativeradioplayer/RadioPlayerModule.kt +++ b/android/src/main/java/com/reactnativeradioplayer/RadioPlayerModule.kt @@ -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 = 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) + } } diff --git a/example/android/RadioPlayerExample.iml b/example/android/RadioPlayerExample.iml new file mode 100644 index 0000000..de23780 --- /dev/null +++ b/example/android/RadioPlayerExample.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/android/app/app.iml b/example/android/app/app.iml new file mode 100644 index 0000000..3a8d517 --- /dev/null +++ b/example/android/app/app.iml @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index bbcb2dc..7d450dc 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -132,6 +132,7 @@ android { targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" + multiDexEnabled true } splits { abi { @@ -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 diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index ecd3b04..8713c64 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ package="com.example.reactnativeradioplayer"> + (); React.useEffect(() => { - RadioPlayerEvents.addListener('StateDidChange', setPlayerState); - RadioPlayerEvents.addListener( - 'PlaybackStateDidChange', - setPlayerPlaybackState - ); + RadioPlayerEvents.addListener('StateDidChange', (eventObject) => { + setPlayerState(eventObject.state); + }); + RadioPlayerEvents.addListener('PlaybackStateDidChange', (eventObject) => { + setPlayerPlaybackState(eventObject.playbackState); + }); return () => { - RadioPlayerEvents.removeListener('StateDidChange', setPlayerState); + RadioPlayerEvents.removeListener('StateDidChange', (eventObject) => { + setPlayerState(eventObject.state); + }); RadioPlayerEvents.removeListener( 'PlaybackStateDidChange', - setPlayerPlaybackState + (eventObject) => { + setPlayerPlaybackState(eventObject.playbackState); + } ); }; }, []); @@ -28,7 +33,7 @@ export default function App() { RadioPlayerEvents.addListener('MetadataDidChange', setMetadata); React.useEffect(() => { - RadioPlayer.radioURL('https://stream.fr.morow.com/morow_med.aacp'); + RadioPlayer.radioURL('http://stream.fr.morow.com/morow_med.aacp'); return () => { RadioPlayer.stop(); }; diff --git a/ios/RadioPlayer.swift b/ios/RadioPlayer.swift index 38fcb4d..3c163f7 100644 --- a/ios/RadioPlayer.swift +++ b/ios/RadioPlayer.swift @@ -79,7 +79,7 @@ class RadioPlayer: RCTEventEmitter, FRadioPlayerDelegate { } print("player \(player) player state did change to \(stateString ?? "Unknown")") if (hasListeners) { - sendEvent(withName: "StateDidChange", body: stateString) + sendEvent(withName: "StateDidChange", body: ["state": stateString]) } } @@ -95,7 +95,7 @@ class RadioPlayer: RCTEventEmitter, FRadioPlayerDelegate { } print("player \(player) playback state did change to \(playbackStateString ?? "Unknown")") if (hasListeners) { - sendEvent(withName: "PlaybackStateDidChange", body: playbackStateString) + sendEvent(withName: "PlaybackStateDidChange", body: ["playbackState": playbackStateString]) } }