Skip to content

Commit

Permalink
First Strike
Browse files Browse the repository at this point in the history
  • Loading branch information
Xerus committed Feb 13, 2018
0 parents commit baedea1
Show file tree
Hide file tree
Showing 9 changed files with 327 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.gradle
/build/

.idea
/out/
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# mpris-java
Simple MPRIS 2 implementation with Kotlin for Java

This is not done, but usable. No guarantees whatsoever.

Look into xerus.mpris.MPRISPlayer for a test implementation.

### Todo
- TrackList
- better Properties integration
30 changes: 30 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
application
kotlin("jvm") version "1.1.51"
}

java.sourceSets["main"].java.srcDir("src/main")
java.sourceSets["test"].java.srcDir("src/test")

group = "xerus.mpris"

application {
mainClassName = "xerus.mpris.MPRISPlayerKt"
}

repositories {
jcenter()
}

dependencies {
compile("com.github.hypfvieh", "dbus-java", "2.7.4")
compile(kotlin("runtime"))
}

tasks {
withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
}
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = "mpris-java"
43 changes: 43 additions & 0 deletions src/main/org/mpris/MediaPlayer2/Player.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@file: Suppress("UNUSED")
package org.mpris.MediaPlayer2

import org.freedesktop.DBus
import org.freedesktop.dbus.DBusInterface
import org.freedesktop.dbus.DBusInterfaceName
import org.freedesktop.dbus.DBusSignal
import org.freedesktop.dbus.Variant

interface DefaultDBus: DBus.Properties {
override fun isRemote() = false
@Suppress("UNCHECKED_CAST")
override fun <A: Any?> Get(interface_name: String, property_name: String): A {
return GetAll(interface_name)[property_name]?.value as A
}
override fun <A: Any?> Set(interface_name: String, property_name: String, value: A) {
GetAll(interface_name).put(property_name, Variant(value))
}
}

@DBusInterfaceName("org.mpris.MediaPlayer2")
interface MediaPlayer2: DBusInterface {
fun Raise()
fun Quit()
}

@DBusInterfaceName("org.mpris.MediaPlayer2.Player")
interface Player: DBusInterface {
class Seeked(path: String, val position: Long): DBusSignal(path, position)

fun Next()
fun Previous()
fun Pause()
fun PlayPause()
fun Play()
fun Stop()
fun Seek(x: Long)
fun OpenUri(uri: String)
}

enum class PlaybackStatus {
Playing, Paused, Stopped
}
30 changes: 30 additions & 0 deletions src/main/org/mpris/MediaPlayer2/Playlists.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@file: Suppress("UNUSED")
package org.mpris.MediaPlayer2

import org.freedesktop.dbus.DBusInterface
import org.freedesktop.dbus.DBusInterfaceName
import org.freedesktop.dbus.DBusSignal
import org.freedesktop.dbus.Position
import org.freedesktop.dbus.Struct
import org.freedesktop.dbus.UInt32

@DBusInterfaceName("org.mpris.MediaPlayer2.Playlists")
interface Playlists: DBusInterface {
class PlaylistChanged(path: String, val playlist: Struct2): DBusSignal(path, playlist)
fun ActivatePlaylist(playlist_id: DBusInterface)
fun GetPlaylists(index: UInt32, max_count: UInt32, order: String, reverse_order: Boolean): List<Playlist>
}

class Playlist(@field:Position(0)
val a: DBusInterface,
@field:Position(1)
val b: String,
@field:Position(2)
val c: String): Struct()

class Struct2(@field:Position(0)
val a: DBusInterface,
@field:Position(1)
val b: String,
@field:Position(2)
val c: String): Struct()
31 changes: 31 additions & 0 deletions src/main/org/mpris/MediaPlayer2/TrackList.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
@file: Suppress("UNUSED")
package org.mpris.MediaPlayer2

import org.freedesktop.dbus.DBusInterface
import org.freedesktop.dbus.DBusSignal
import org.freedesktop.dbus.Variant

interface TrackList: DBusInterface {

class TrackListReplacedr(path: String, val Tracks: List<DBusInterface>,
val CurrentTrack: DBusInterface): DBusSignal(path, Tracks, CurrentTrack)

class TrackAdded(path: String, val Metadata: Map<String, Variant<*>>,
val AfterTrack: DBusInterface): DBusSignal(path, Metadata, AfterTrack)

class TrackRemoved(path: String, val TrackId: DBusInterface): DBusSignal(path, TrackId)

class TrackMetadataChanged(path: String, val TrackId: DBusInterface,
val Metadata: Map<String, Variant<*>>): DBusSignal(path, TrackId, Metadata)

fun GetTracksMetadata(
TrackIds: List<DBusInterface>): List<Map<String, Variant<*>>>

fun AddTrack(Uri: String, AfterTrack: DBusInterface,
SetAsCurrent: Boolean)

fun RemoveTrack(TrackId: DBusInterface)

fun GoTo(TrackId: DBusInterface)

}
158 changes: 158 additions & 0 deletions src/main/xerus/mpris/MPRISPlayer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package xerus.mpris

import org.freedesktop.DBus.Properties.PropertiesChanged
import org.freedesktop.dbus.DBusConnection
import org.freedesktop.dbus.Variant
import org.freedesktop.dbus.types.DBusMapType
import org.mpris.MediaPlayer2.DefaultDBus
import org.mpris.MediaPlayer2.MediaPlayer2
import org.mpris.MediaPlayer2.PlaybackStatus
import org.mpris.MediaPlayer2.Player
import java.util.Collections
import java.util.HashMap

val conn = DBusConnection.getConnection(DBusConnection.SESSION)

fun println(obj: String) = System.out.println(obj)
operator fun <K, V> HashMap<K, V>.set(k: K, value: V) = put(k, value)

fun main(args: Array<String>) {
println("Connecting to DBus")
conn.requestBusName("org.mpris.MediaPlayer2.PlayerFX")
conn.exportObject("/org/mpris/MediaPlayer2", MPRISPlayer())
}

class MPRISPlayer : MediaPlayer2, Player, DefaultDBus {

val properties = HashMap<String, PropertyMap>()

var status = PlaybackStatus.Stopped

init {
println("Constructing MPRISPlayer")
// MediaPlayer2
properties["org.mpris.MediaPlayer2"] = PropertyMap {
put("CanSeek", true)
put("CanSeek", true)
put("CanQuit", true)
put("CanRaise", false)
put("HasTrackList", true)
put("Identity", "PlayerFX")
put("SupportedUriSchemes", arrayOf("file"))
put("SupportedMimeTypes", arrayOf("audio/mpeg", "audio/mp4"))
//properties["DesktopEntry"]
}

// Player
properties["org.mpris.MediaPlayer2.Player"] = PropertyMap {
put("PlaybackStatus", status)
put("LoopStatus", "None")
put("Rate", 1.0)
put("Shuffle", false)
put("Metadata", Variant(
PropertyMap {
put("mpris:trackid", "/song/1")
put("mpris:length", 10_000000)
put("mpris:artUrl", "file:///home/janek/Daten/Musik/Monstercat/Aero Chord - Love & Hate EP/cover.jpeg")
put("xesam:artist", arrayOf("Aero Chord", "Fractal"))
put("xesam:title", "Until The End (feat. Q'AILA)")
},
DBusMapType(Class.forName("java.lang.String"), Class.forName("org.freedesktop.dbus.Variant"))))
put("Volume", 1.0)
put("Position", 0)
put("MinimumRate", 1.0)
put("MaximumRate", 1.0)
put("CanGoNext", true)
put("CanGoPrevious", true)
put("CanPlay", true)
put("CanPause", true)
put("CanSeek", true)
put("CanControl", true)
}

// Playlist
/*properties["PlaylistCount"] = Variant()
// u Read only
properties["Orderings"] = Variant()
// as (Playlist_Ordering_List) Read only
properties["ActivePlaylist"] = Variant()
// (b(oss)) (Maybe_Playlist) Read only
*/

// TrackList
/*properties["Tracks"] = Variant()
// ao (Track_Id_List) Read only
properties["CanEditTracks"] = Variant()
// b Read only*/
println("MPRISPlayer constructed")
}

override fun GetAll(interface_name: String): Map<String, Variant<*>> = properties[interface_name]!!

fun <A: Any> updateProperty(interface_name: String, name: String, value: A) {
println("Updating $name of $interface_name to $value")
val new = Variant(value)
properties[interface_name]!![name] = new
try {
conn.sendSignal(PropertiesChanged("/org/mpris/MediaPlayer2", interface_name, Collections.singletonMap(name, new) as Map<String, Variant<*>>, Collections.emptyList()))
} catch (e: Throwable) {
e.printStackTrace()
}
}

fun updateStatus(status: PlaybackStatus) {
this.status = status
updateProperty("org.mpris.MediaPlayer2.Player", "PlaybackStatus", status.name)
}

override fun PlayPause() {
println("PlayPause called")
if(status == PlaybackStatus.Playing)
updateStatus(PlaybackStatus.Paused)
else
updateStatus(PlaybackStatus.Playing)
}

override fun Play() {
println("Play called")
updateStatus(PlaybackStatus.Playing)
}

override fun Pause() {
println("Pause called")
updateStatus(PlaybackStatus.Paused)
}

override fun Stop() {
println("Stop called")
updateStatus(PlaybackStatus.Stopped)
}

override fun Seek(x: Long) {
println("Seeking by $x")
}

override fun Previous() {
println("Previous called")
}

override fun Next() {
println("Next called")
}

override fun Raise() {
println("open me!")
}

override fun Quit() {
println("I'm quitting!")
conn.disconnect()
}

override fun OpenUri(uri: String) {
println("OpenUri called")
}

override fun getObjectPath() = "/org/mpris/MediaPlayer2"

}
19 changes: 19 additions & 0 deletions src/main/xerus/mpris/Properties.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package xerus.mpris

import org.freedesktop.dbus.Variant
import java.util.HashMap

class PropertyMap(initial: PropertyMap.() -> Unit): HashMap<String, Variant<*>>() {

init {
initial(this)
}

fun put(key: String, value: Any) {
var v = value
if(value is Enum<*>)
v = value.name
super.put(key, Variant(v))
}

}

0 comments on commit baedea1

Please sign in to comment.