Merge branch 'mediasession' of https://github.com/DDRBoxman/MPD
This commit is contained in:
commit
3e862b85d4
|
@ -70,6 +70,8 @@ dependencies {
|
||||||
ksp("com.google.dagger:dagger-compiler:2.49")
|
ksp("com.google.dagger:dagger-compiler:2.49")
|
||||||
ksp("com.google.dagger:hilt-compiler:2.49")
|
ksp("com.google.dagger:hilt-compiler:2.49")
|
||||||
|
|
||||||
|
implementation("androidx.media3:media3-session:1.2.0")
|
||||||
|
|
||||||
// Android Studio Preview support
|
// Android Studio Preview support
|
||||||
implementation("androidx.compose.ui:ui-tooling-preview")
|
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||||
debugImplementation("androidx.compose.ui:ui-tooling")
|
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||||
|
|
|
@ -18,4 +18,6 @@ public class Bridge {
|
||||||
public static native void run(Context context, LogListener logListener);
|
public static native void run(Context context, LogListener logListener);
|
||||||
public static native void shutdown();
|
public static native void shutdown();
|
||||||
public static native void pause();
|
public static native void pause();
|
||||||
|
public static native void playNext();
|
||||||
|
public static native void playPrevious();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
package org.musicpd;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.media3.common.Player;
|
||||||
|
import androidx.media3.common.SimpleBasePlayer;
|
||||||
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@UnstableApi
|
||||||
|
public class MPDPlayer extends SimpleBasePlayer {
|
||||||
|
|
||||||
|
List<MediaItemData> placeholderItems;
|
||||||
|
public MPDPlayer(Looper looper) {
|
||||||
|
super(looper);
|
||||||
|
|
||||||
|
// Dummy items to let us receive next and previous commands
|
||||||
|
MediaItemData item0 = new MediaItemData.Builder(0)
|
||||||
|
.build();
|
||||||
|
MediaItemData item1 = new MediaItemData.Builder(1)
|
||||||
|
.build();
|
||||||
|
MediaItemData item2 = new MediaItemData.Builder(2)
|
||||||
|
.build();
|
||||||
|
MediaItemData[] items = new MediaItemData[] { item0, item1, item2 };
|
||||||
|
|
||||||
|
placeholderItems = Arrays.asList(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected State getState() {
|
||||||
|
Commands commands = new Commands.Builder().addAll(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT_MEDIA_ITEM).build();
|
||||||
|
|
||||||
|
return new State.Builder()
|
||||||
|
.setAvailableCommands(commands)
|
||||||
|
.setPlaybackState(Player.STATE_READY)
|
||||||
|
.setPlaylist(placeholderItems)
|
||||||
|
.setCurrentMediaItemIndex(1)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@SuppressLint("SwitchIntDef")
|
||||||
|
@Override
|
||||||
|
protected ListenableFuture<?> handleSeek(int mediaItemIndex, long positionMs, int seekCommand) {
|
||||||
|
switch (seekCommand) {
|
||||||
|
case COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM:
|
||||||
|
case COMMAND_SEEK_TO_PREVIOUS:
|
||||||
|
Bridge.playPrevious();
|
||||||
|
break;
|
||||||
|
case COMMAND_SEEK_TO_NEXT_MEDIA_ITEM:
|
||||||
|
case COMMAND_SEEK_TO_NEXT:
|
||||||
|
Bridge.playNext();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Futures.immediateVoidFuture();
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,11 +16,16 @@ import android.content.ServiceConnection;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.Looper;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.RemoteCallbackList;
|
import android.os.RemoteCallbackList;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.OptIn;
|
||||||
|
import androidx.media3.common.util.UnstableApi;
|
||||||
|
import androidx.media3.session.MediaSession;
|
||||||
|
|
||||||
import org.musicpd.data.LoggingRepository;
|
import org.musicpd.data.LoggingRepository;
|
||||||
import org.musicpd.ui.SettingsActivity;
|
import org.musicpd.ui.SettingsActivity;
|
||||||
|
|
||||||
|
@ -51,6 +56,8 @@ public class Main extends Service implements Runnable {
|
||||||
private boolean mPauseOnHeadphonesDisconnect = false;
|
private boolean mPauseOnHeadphonesDisconnect = false;
|
||||||
private PowerManager.WakeLock mWakelock = null;
|
private PowerManager.WakeLock mWakelock = null;
|
||||||
|
|
||||||
|
private MediaSession mMediaSession = null;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
LoggingRepository logging;
|
LoggingRepository logging;
|
||||||
|
|
||||||
|
@ -184,6 +191,7 @@ public class Main extends Service implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(markerClass = UnstableApi.class)
|
||||||
private void start() {
|
private void start() {
|
||||||
if (mThread != null)
|
if (mThread != null)
|
||||||
return;
|
return;
|
||||||
|
@ -225,11 +233,16 @@ public class Main extends Service implements Runnable {
|
||||||
mThread = new Thread(this);
|
mThread = new Thread(this);
|
||||||
mThread.start();
|
mThread.start();
|
||||||
|
|
||||||
|
MPDPlayer player = new MPDPlayer(Looper.getMainLooper());
|
||||||
|
mMediaSession = new MediaSession.Builder(this, player).build();
|
||||||
|
|
||||||
startForeground(R.string.notification_title_mpd_running, notification);
|
startForeground(R.string.notification_title_mpd_running, notification);
|
||||||
startService(new Intent(this, Main.class));
|
startService(new Intent(this, Main.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stop() {
|
private void stop() {
|
||||||
|
mMediaSession.release();
|
||||||
|
mMediaSession = null;
|
||||||
if (mThread != null) {
|
if (mThread != null) {
|
||||||
if (mThread.isAlive()) {
|
if (mThread.isAlive()) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
|
22
src/Main.cxx
22
src/Main.cxx
|
@ -614,6 +614,28 @@ Java_org_musicpd_Bridge_pause(JNIEnv *, jclass)
|
||||||
partition.pc.LockSetPause(true);
|
partition.pc.LockSetPause(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gcc_visibility_default
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_musicpd_Bridge_playNext(JNIEnv *, jclass)
|
||||||
|
{
|
||||||
|
if (global_instance != nullptr)
|
||||||
|
BlockingCall(global_instance->event_loop, [&](){
|
||||||
|
for (auto &partition : global_instance->partitions)
|
||||||
|
partition.PlayNext();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_visibility_default
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_org_musicpd_Bridge_playPrevious(JNIEnv *, jclass)
|
||||||
|
{
|
||||||
|
if (global_instance != nullptr)
|
||||||
|
BlockingCall(global_instance->event_loop, [&](){
|
||||||
|
for (auto &partition : global_instance->partitions)
|
||||||
|
partition.PlayPrevious();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|
Loading…
Reference in New Issue