Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
boyan01 committed Sep 7, 2023
1 parent 01a195f commit 96563ec
Show file tree
Hide file tree
Showing 29 changed files with 704 additions and 691 deletions.
1 change: 0 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ apply plugin: 'kotlin-android-extensions'

android {
compileSdkVersion 31
buildToolsVersion "33.0.0"

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
Expand Down
17 changes: 17 additions & 0 deletions android/src/main/aidl/tech/soit/quiet/ISessionDataProvider.aidl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// ISessionDataProvider.aidl
package tech.soit.quiet;

import tech.soit.quiet.player.MusicMetadata;
import tech.soit.quiet.MusicResult;

parcelable ArtworkData;

interface ISessionDataProvider {

ArtworkData loadArtwork(in MusicMetadata metadata);

String getPlayerUrl(String id, String fallbackUrl);

}


30 changes: 30 additions & 0 deletions android/src/main/kotlin/tech/soit/quiet/ArtworkData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package tech.soit.quiet

import android.os.Parcel
import android.os.Parcelable

class ArtworkData(
val color: Int?,
val image: ByteArray
) : Parcelable {

constructor(source: Parcel) : this(
source.readValue(Int::class.java.classLoader) as Int?,
source.createByteArray()!!
)

override fun describeContents() = 0

override fun writeToParcel(dest: Parcel, flags: Int) = with(dest) {
writeValue(color)
writeByteArray(image)
}

companion object {
@JvmField
val CREATOR: Parcelable.Creator<ArtworkData> = object : Parcelable.Creator<ArtworkData> {
override fun createFromParcel(source: Parcel): ArtworkData = ArtworkData(source)
override fun newArray(size: Int): Array<ArtworkData?> = arrayOfNulls(size)
}
}
}
190 changes: 188 additions & 2 deletions android/src/main/kotlin/tech/soit/quiet/MusicPlayerUiPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.net.Uri
import android.os.IBinder
import android.os.SystemClock
import com.google.android.exoplayer2.*
import com.google.android.exoplayer2.audio.AudioAttributes
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DefaultDataSource
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
Expand All @@ -23,11 +30,11 @@ private const val UI_PLUGIN_NAME = "tech.soit.quiet/player.ui"

class MusicPlayerUiPlugin : FlutterPlugin {

private var playerUiChannel: MusicPlayerUiChannel? = null
private var playerUiChannel: AudioPlayerChannel? = null

override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
val channel = MethodChannel(binding.binaryMessenger, UI_PLUGIN_NAME)
playerUiChannel = MusicPlayerUiChannel(channel, binding.applicationContext)
playerUiChannel = AudioPlayerChannel(channel, binding.applicationContext)
channel.setMethodCallHandler(playerUiChannel)
}

Expand All @@ -38,6 +45,185 @@ class MusicPlayerUiPlugin : FlutterPlugin {
}


class AudioPlayerChannel(
private val channel: MethodChannel,
private val context: Context
) : MethodChannel.MethodCallHandler {

companion object {
var lastCreatedPlayerId = 0L
}

init {
channel.setMethodCallHandler(this)
}

private val players = mutableMapOf<Long, AudioPlayer>()

override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"createPlayer" -> {
val uri = Uri.parse(call.argument("uri"))
val playerId = ++lastCreatedPlayerId
players[playerId] = AudioPlayer(playerId, uri, context, channel)
result.success(playerId)
}
"prepare" -> {
val playerId = call.argument<Long>("id")!!
val playWhenReady = call.argument<Boolean>("playWhenReady")!!
players[playerId]?.prepare(playWhenReady)
result.success(null)
}
"setPlayWhenReady" -> {
val playerId = call.argument<Long>("id")!!
val playWhenReady = call.argument<Boolean>("playWhenReady")!!
players[playerId]?.setPlayWhenReady(playWhenReady)
result.success(null)
}

"setVolume" -> {
val playerId = call.argument<Long>("id")!!
val volume = call.argument<Double>("volume")!!
players[playerId]?.setVolume(volume.toFloat())
result.success(null)
}
"seekTo" -> {
val playerId = call.argument<Long>("id")!!
val position = call.argument<Long>("position")!!
players[playerId]?.seekTo(position)
result.success(null)
}
"getBufferedPosition" -> {
val playerId = call.argument<Long>("id")!!
val position = players[playerId]?.getBufferedPosition()
result.success(position)
}
"dispose" -> {
val playerId = call.argument<Long>("id")!!
players[playerId]?.release()
players.remove(playerId)
result.success(null)
}
else -> {
result.notImplemented()
}

}
}

fun destroy() {
players.values.forEach { it.release() }
players.clear()
}

}

class AudioPlayer(
private val playerId: Long,
uri: Uri,
context: Context,
private val channel: MethodChannel
) : Player.Listener {

companion object {
private val audioAttribute = AudioAttributes.Builder()
.setContentType(C.AUDIO_CONTENT_TYPE_MUSIC)
.setUsage(C.USAGE_MEDIA)
.build()
}

// Wrap a SimpleExoPlayer with a decorator to handle audio focus for us.
private val player: ExoPlayer = ExoPlayer.Builder(context)
.setAudioAttributes(audioAttribute, true)
.build()


init {
val factory: DataSource.Factory = DefaultDataSource.Factory(context)
player.setMediaSource(
ProgressiveMediaSource.Factory(factory)
.createMediaSource(MediaItem.fromUri(uri))
)
player.addListener(this)
}

fun setPlayWhenReady(playWhenReady: Boolean) {
player.playWhenReady = playWhenReady
}

fun prepare(playWhenReady: Boolean) {
player.prepare()
player.playWhenReady = playWhenReady
}

fun setVolume(volume: Float) {
player.volume = volume
}

fun seekTo(position: Long) {
player.seekTo(position)
}

fun release() {
player.release()
}

fun getBufferedPosition(): Long {
return player.bufferedPosition
}

override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
notifyPositionChanged()
channel.invokeMethod(
"onPlayWhenReadyChanged", mapOf(
"id" to playerId,
"playWhenReady" to playWhenReady,
"reason" to reason,
)
)
}

private fun notifyPositionChanged() {
channel.invokeMethod(
"onPositionChanged", mapOf(
"id" to playerId,
"position" to player.currentPosition,
"duration" to player.duration,
"updateTime" to SystemClock.elapsedRealtime(),
)
)
}

override fun onPositionDiscontinuity(
oldPosition: Player.PositionInfo,
newPosition: Player.PositionInfo,
reason: Int
) {
notifyPositionChanged()
}

override fun onPlaybackStateChanged(playbackState: Int) {
channel.invokeMethod(
"onPlaybackStateChanged", mapOf(
"id" to playerId,
"playbackState" to playbackState,
"duration" to player.duration,
)
)
}

override fun onPlayerError(error: PlaybackException) {
channel.invokeMethod(
"onPlayerError", mapOf(
"id" to playerId,
"errorCode" to error.errorCode,
"message" to error.message,
)
)
}

}

private class MusicPlayerUiChannel(
channel: MethodChannel,
context: Context
Expand Down
2 changes: 1 addition & 1 deletion example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ android {
applicationId "tech.soit.example"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
minSdkVersion flutter.minSdkVersion
minSdkVersion 21
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
Expand Down
1 change: 1 addition & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'package:logging/logging.dart';
import 'package:music_player_example/page_play_queue.dart';
import 'package:overlay_support/overlay_support.dart';

import 'player/music_metadata.dart';
import 'player/player.dart';
import 'player/player_bottom_controller.dart';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'package:music_player_example/player/player.dart';

/// Music metadata
class MusicMetadata {
class MusicMetadata extends PlayItem {
final Map? extras;
final String mediaId;
final String? mediaUri;
Expand Down Expand Up @@ -47,4 +49,9 @@ class MusicMetadata {
String toString() {
return 'MusicMetadata{mediaId: $mediaId, title: $title, subtitle: $subtitle}';
}

@override
Future<String> playerUrl() {
return Future.value(mediaUri!);
}
}
56 changes: 56 additions & 0 deletions example/lib/player/queue.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import 'package:music_player_example/player/player.dart';

class AppPlayQueue implements PlayQueue {
final String queueId;

final List<PlayItem> queue;

bool get isEmpty => queue.isEmpty;

const AppPlayQueue({
required this.queueId,
required this.queue,
});

const AppPlayQueue.empty()
: this(
queueId: "empty",
queue: const [],
);

@override
Future<PlayItem?> getNext(PlayItem? current) async {
if (isEmpty) {
return null;
}
if (current == null) {
return queue.first;
}
final index = queue.indexOf(current);
if (index == -1) {
return null;
}
if (index == queue.length - 1) {
return null;
}
return queue[index + 1];
}

@override
Future<PlayItem?> getPrevious(PlayItem? current) async {
if (isEmpty) {
return null;
}
if (current == null) {
return queue.first;
}
final index = queue.indexOf(current);
if (index == -1) {
return null;
}
if (index == 0) {
return null;
}
return queue[index - 1];
}
}
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -213,5 +213,5 @@ packages:
source: hosted
version: "2.1.4"
sdks:
dart: ">=2.18.0 <3.0.0"
dart: ">=2.19.0 <3.0.0"
flutter: ">=3.0.0"
2 changes: 1 addition & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Demonstrates how to use the flutter_music_player plugin.
publish_to: 'none'

environment:
sdk: ">=2.6.0 <3.0.0"
sdk: ">=2.19.0 <3.0.0"

dependencies:
flutter:
Expand Down
10 changes: 1 addition & 9 deletions lib/music_player.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1 @@
export 'src/channel_ui.dart';
export "src/model/playback_error.dart";
export 'src/player/music_metadata.dart';
export 'src/player/play_mode.dart';
export 'src/player/play_queue.dart';
export 'src/player/playback_state.dart';
export 'src/player/transport_controls.dart';
export 'src/utils/interceptor.dart';
export 'src/utils/progress_track_container.dart';
export 'src/queue.dart';
Loading

0 comments on commit 96563ec

Please sign in to comment.