Skip to content

Commit

Permalink
Merge pull request #13 from matejdro/music
Browse files Browse the repository at this point in the history
Music control packets
  • Loading branch information
crc-32 authored Dec 24, 2020
2 parents 0e1102b + 671df66 commit 5a4cc6e
Show file tree
Hide file tree
Showing 12 changed files with 421 additions and 15 deletions.
15 changes: 15 additions & 0 deletions src/androidMain/kotlin/util/DataBuffer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,33 @@ actual class DataBuffer {
actual constructor(size: Int) {
actualBuf = ByteBuffer.allocate(size)
}

actual constructor(bytes: UByteArray) {
actualBuf = ByteBuffer.wrap(bytes.toByteArray())
}

/**
* Total length of the buffer
*/
actual val length: Int
get() = actualBuf.capacity()

/**
* Current position in the buffer
*/
actual val readPosition: Int
get() = actualBuf.position()

actual fun putUShort(short: UShort) {
actualBuf.putShort(short.toShort())
}

actual fun getUShort(): UShort = actualBuf.short.toUShort()

actual fun putShort(short: Short) {
actualBuf.putShort(short)
}

actual fun getShort(): Short = actualBuf.short

actual fun putUByte(byte: UByte) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.rebble.libpebblecommon.exceptions

class PacketEncodeException(message: String?): Exception(message)
class PacketDecodeException(message: String?): Exception(message)
class PacketEncodeException(message: String?) : Exception(message)
class PacketDecodeException(message: String?, cause: Exception? = null) : Exception(message, cause)
168 changes: 168 additions & 0 deletions src/commonMain/kotlin/io/rebble/libpebblecommon/packets/Music.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package io.rebble.libpebblecommon.packets

import io.rebble.libpebblecommon.protocolhelpers.PacketRegistry
import io.rebble.libpebblecommon.protocolhelpers.PebblePacket
import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint
import io.rebble.libpebblecommon.structmapper.*

open class MusicControl(val message: Message) : PebblePacket(ProtocolEndpoint.MUSIC_CONTROL) {
val command = SUByte(m, message.value)

init {
type = command.get()
}

enum class Message(val value: UByte) {
PlayPause(0x01u),
Pause(0x02u),
Play(0x03u),
NextTrack(0x04u),
PreviousTrack(0x05u),
VolumeUp(0x06u),
VolumeDown(0x07u),
GetCurrentTrack(0x08u),
UpdateCurrentTrack(0x10u),
UpdatePlayStateInfo(0x11u),
UpdateVolumeInfo(0x12u),
UpdatePlayerInfo(0x13u)
}

class UpdateCurrentTrack(
artist: String = "",
album: String = "",
title: String = "",
trackLength: Int? = null,
trackCount: Int? = null,
currentTrack: Int? = null
) : MusicControl(Message.UpdateCurrentTrack) {
val artist = SString(m, artist)
val album = SString(m, album)
val title = SString(m, title)
val trackLength = SOptional(
m,
SUInt(StructMapper(), trackLength?.toUInt() ?: 0u, '<'),
trackLength != null
)
val trackCount = SOptional(
m,
SUInt(StructMapper(), trackCount?.toUInt() ?: 0u, '<'),
trackCount != null
)
val currentTrack = SOptional(
m,
SUInt(StructMapper(), currentTrack?.toUInt() ?: 0u, '<'),
currentTrack != null
)
}

class UpdatePlayStateInfo(
playbackState: PlaybackState = PlaybackState.Unknown,
trackPosition: UInt = 0u,
playRate: UInt = 0u,
shuffle: ShuffleState = ShuffleState.Unknown,
repeat: RepeatState = RepeatState.Unknown
) : MusicControl(Message.UpdatePlayStateInfo) {
val state = SUByte(m, playbackState.value)
val trackPosition = SUInt(m, trackPosition, '<')
val playRate = SUInt(m, playRate, '<')
val shuffle = SUByte(m, shuffle.value)
val repeat = SUByte(m, repeat.value)
}

class UpdateVolumeInfo(
volumePercent: UByte = 0u,
) : MusicControl(Message.UpdateVolumeInfo) {
val volumePercent = SUByte(m, volumePercent)
}

class UpdatePlayerInfo(
pkg: String = "",
name: String = ""
) : MusicControl(Message.UpdatePlayerInfo) {
val pkg = SString(m, pkg)
val name = SString(m, name)
}

enum class PlaybackState(val value: UByte) {
Paused(0x00u),
Playing(0x01u),
Rewinding(0x02u),
FastForwarding(0x03u),
Unknown(0x04u),
}

enum class ShuffleState(val value: UByte) {
Unknown(0x00u),
Off(0x01u),
On(0x02u),
}

enum class RepeatState(val value: UByte) {
Unknown(0x00u),
Off(0x01u),
One(0x02u),
All(0x03u),
}
}

fun musicPacketsRegister() {
PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.PlayPause.value
) { MusicControl(MusicControl.Message.PlayPause) }

PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.Pause.value
) { MusicControl(MusicControl.Message.Pause) }

PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.Play.value
) { MusicControl(MusicControl.Message.Play) }

PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.NextTrack.value
) { MusicControl(MusicControl.Message.NextTrack) }

PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.PreviousTrack.value
) { MusicControl(MusicControl.Message.PreviousTrack) }

PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.VolumeUp.value
) { MusicControl(MusicControl.Message.VolumeUp) }

PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.VolumeDown.value
) { MusicControl(MusicControl.Message.VolumeDown) }

PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.GetCurrentTrack.value
) { MusicControl(MusicControl.Message.GetCurrentTrack) }

PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.UpdateCurrentTrack.value
) { MusicControl.UpdateCurrentTrack() }

PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.UpdatePlayStateInfo.value
) { MusicControl.UpdatePlayStateInfo() }

PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.UpdateVolumeInfo.value
) { MusicControl.UpdateVolumeInfo() }

PacketRegistry.register(
ProtocolEndpoint.MUSIC_CONTROL,
MusicControl.Message.UpdatePlayerInfo.value
) { MusicControl.UpdatePlayerInfo() }
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
package io.rebble.libpebblecommon.protocolhelpers

import io.rebble.libpebblecommon.exceptions.PacketDecodeException
import io.rebble.libpebblecommon.packets.appRunStatePacketsRegister
import io.rebble.libpebblecommon.packets.appmessagePacketsRegister
import io.rebble.libpebblecommon.packets.*
import io.rebble.libpebblecommon.packets.blobdb.blobDBPacketsRegister
import io.rebble.libpebblecommon.packets.blobdb.timelinePacketsRegister
import io.rebble.libpebblecommon.packets.systemPacketsRegister
import io.rebble.libpebblecommon.packets.timePacketsRegister

/**
* Singleton to track endpoint / type discriminators for deserialization
Expand All @@ -22,6 +19,7 @@ object PacketRegistry {
blobDBPacketsRegister()
appmessagePacketsRegister()
appRunStatePacketsRegister()
musicPacketsRegister()
}

/**
Expand All @@ -46,7 +44,7 @@ object PacketRegistry {

val typeOffset = if (typeOffsets[endpoint] != null) typeOffsets[endpoint]!! else 4
val decoder = epdecoders[packet[typeOffset]]
?: throw PacketDecodeException("No packet class registered for endpoint $endpoint")
?: throw PacketDecodeException("No packet class registered for type ${packet[typeOffset]} of $endpoint")
return decoder(packet)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,19 @@ open class PebblePacket{
val length = SUShort(meta)
val ep = SUShort(meta)
meta.fromBytes(buf)
if (packet.size <= (2*UShort.SIZE_BYTES))
if (packet.size <= (2 * UShort.SIZE_BYTES))
throw PacketDecodeException("Malformed packet: contents empty")
if (length.get().toInt() != (packet.size - (2*UShort.SIZE_BYTES)))
if (length.get().toInt() != (packet.size - (2 * UShort.SIZE_BYTES)))
throw PacketDecodeException("Malformed packet: bad length")
val ret = PacketRegistry.get(
ProtocolEndpoint.getByValue(ep.get()),
packet
)
ret.m.fromBytes(buf)
try {
ret.m.fromBytes(buf)
} catch (e: Exception) {
throw PacketDecodeException("Failed to decode packet $ret", e)
}
return ret
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.rebble.libpebblecommon.services

import io.rebble.libpebblecommon.ProtocolHandler
import io.rebble.libpebblecommon.packets.MusicControl
import io.rebble.libpebblecommon.protocolhelpers.PebblePacket
import io.rebble.libpebblecommon.protocolhelpers.ProtocolEndpoint
import kotlinx.coroutines.channels.Channel

class MusicService(private val protocolHandler: ProtocolHandler) : ProtocolService {
val receivedMessages = Channel<MusicControl>(Channel.BUFFERED)

init {
protocolHandler.registerReceiveCallback(ProtocolEndpoint.MUSIC_CONTROL, this::receive)
}

suspend fun send(packet: MusicControl) {
protocolHandler.send(packet)
}

fun receive(packet: PebblePacket) {
if (packet !is MusicControl) {
throw IllegalStateException("Received invalid packet type: $packet")
}

receivedMessages.offer(packet)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ class SystemService(private val protocolHandler: ProtocolHandler) : ProtocolServ
2u,
ProtocolCapsFlag.makeFlags(
listOf(
ProtocolCapsFlag.Supports8kAppMessage
ProtocolCapsFlag.Supports8kAppMessage,
ProtocolCapsFlag.SupportsExtendedMusicProtocol
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,4 +377,41 @@ class SFixedList<T : Mappable>(
override fun hashCode(): Int {
return list.hashCode()
}
}

class SOptional<T>(
mapper: StructMapper,
val value: StructElement<T>,
var present: Boolean
) : Mappable {
init {
mapper.register(this)
}

override fun toBytes(): UByteArray {
return if (present) value.toBytes() else UByteArray(0)
}

override fun fromBytes(bytes: DataBuffer) {
val leftBytes = bytes.length - bytes.readPosition
if (leftBytes < value.size) {
present = false
} else {
present = true
value.fromBytes(bytes)
}
}

fun get(): T? {
return if (present) value.get() else null
}

fun set(value: T?) {
if (value != null) {
present = true
this.value.set(value)
} else {
present = false
}
}
}
10 changes: 10 additions & 0 deletions src/commonMain/kotlin/io/rebble/libpebblecommon/util/DataBuffer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,14 @@ expect class DataBuffer {
fun array(): UByteArray

fun setEndian(endian: Char)

/**
* Total length of the buffer
*/
val length: Int

/**
* Current position in the buffer
*/
val readPosition: Int
}
Loading

0 comments on commit 5a4cc6e

Please sign in to comment.