Compare commits

..

2 Commits

Author SHA1 Message Date
d5d52ad2bd implement studio transition 2023-10-20 11:18:06 -04:00
6b0f5b99f9 obs impl. 2023-10-20 11:16:12 -04:00
7 changed files with 149 additions and 63 deletions

View File

@@ -6,8 +6,12 @@ plugins {
dependencies { dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.3") testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.3")
implementation("com.github.hypfvieh:dbus-java-core:4.3.1") implementation("com.github.hypfvieh:dbus-java-core:4.3.1")
runtimeOnly("com.github.hypfvieh:dbus-java-transport-native-unixsocket:4.3.1") runtimeOnly("com.github.hypfvieh:dbus-java-transport-native-unixsocket:4.3.1")
implementation("io.obs-websocket.community:client:2.0.0")
implementation("org.slf4j:slf4j-api:2.0.9") implementation("org.slf4j:slf4j-api:2.0.9")
runtimeOnly("org.slf4j:slf4j-simple:2.0.9") runtimeOnly("org.slf4j:slf4j-simple:2.0.9")
} }

View File

@@ -0,0 +1,79 @@
package net.eksb.obsdc
import org.freedesktop.dbus.annotations.DBusInterfaceName
import org.freedesktop.dbus.connections.impl.DBusConnection
import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder
import org.freedesktop.dbus.interfaces.DBusInterface
import org.freedesktop.dbus.interfaces.DBusSigHandler
import org.freedesktop.dbus.messages.DBusSignal
import org.slf4j.LoggerFactory
import kotlin.concurrent.thread
class DBus(handler: Handler) {
private val thread = thread(
start = true,
isDaemon = false,
name = "dbus",
) {
DBusConnectionBuilder.forSessionBus().build().use { dbus ->
// These lines are not necessary to handle signals, but are necessary to register methods.
dbus.requestBusName("net.eksb.obsdc")
dbus.exportObject("/", ObsdcDBusInterfaceImpl())
dbus.addSigHandler<ObsdcDBusInterface.Signal> { signal ->
log.info("signal: ${signal.op}")
val op = Op.valueOf(signal.op)
log.info("op: ${op}")
handler.handle(op)
}
while (true) {
try {
Thread.sleep(60_000)
} catch (e:InterruptedException) {
log.info("interrupted")
break
}
}
}
log.info("done")
}
fun stop() {
thread.interrupt()
}
private val log = LoggerFactory.getLogger(DBus::class.java)
}
inline fun <reified T: DBusSignal> DBusConnection.addSigHandler(handler: DBusSigHandler<T>) {
addSigHandler(T::class.java, handler)
}
@DBusInterfaceName("net.eksb.Obsdc")
interface ObsdcDBusInterface: DBusInterface {
fun echo(message:String): String
class Signal(path:String, val op:String): DBusSignal(path, op)
}
class ObsdcDBusInterfaceImpl: ObsdcDBusInterface {
override fun echo(message: String):String {
return message
}
override fun getObjectPath(): String = "/"
}
/*
Monitor:
`dbus-monitor`
See what is registered:
`qdbus net.eksb.obsdc /`
Send signal:
`dbus-send --session --type=signal --dest=net.eksb.obsdc / net.eksb.Obsdc.Signal string:a`
Call method:
`dbus-send --session --type=method_call --print-reply --dest=net.eksb.obsdc / net.eksb.Obsdc.echo string:b`
`qdbus net.eksb.obsdc / net.eksb.Obsdc.echo hello`
*/

View File

@@ -0,0 +1,5 @@
package net.eksb.obsdc
fun interface Handler {
fun handle(op:Op)
}

View File

@@ -1,68 +1,9 @@
package net.eksb.obsdc package net.eksb.obsdc
import org.freedesktop.dbus.annotations.DBusInterfaceName
import org.freedesktop.dbus.connections.impl.DBusConnection
import org.freedesktop.dbus.connections.impl.DBusConnectionBuilder
import org.freedesktop.dbus.interfaces.DBusInterface
import org.freedesktop.dbus.interfaces.DBusSigHandler
import org.freedesktop.dbus.messages.DBusSignal
import org.slf4j.LoggerFactory
object Main { object Main {
@JvmStatic @JvmStatic
fun main(args:Array<String>) { fun main(args: Array<String>) {
val obs = ObsCommunity()
DBusConnectionBuilder.forSessionBus().build().use { dbus -> DBus(obs.handler) // forks non-daemon thread
// These lines are not necessary to handle signals, but are necessary to register methods.
dbus.requestBusName("net.eksb.obsdc")
dbus.exportObject("/", ObsdcDBusInterfaceImpl())
dbus.addSigHandler<ObsdcDBusInterface.Signal> { signal -> log.info("signal: ${signal.message}") }
while (true) {
try {
Thread.sleep(60_000)
} catch (e:InterruptedException) {
log.info("interrupted")
break
}
}
}
log.info("done")
} }
} }
inline fun <reified T:DBusSignal> DBusConnection.addSigHandler(handler:DBusSigHandler<T>) {
addSigHandler(T::class.java, handler)
}
private val log = LoggerFactory.getLogger(Main::class.java)
@DBusInterfaceName("net.eksb.Obsdc")
interface ObsdcDBusInterface: DBusInterface {
fun echo(message:String): String
class Signal(path:String, val message:String): DBusSignal(path, message)
}
class ObsdcDBusInterfaceImpl: ObsdcDBusInterface {
override fun echo(message: String):String {
log.info("echo: ${message}")
return message
}
override fun getObjectPath(): String = "/"
}
/*
Monitor:
`dbus-monitor`
See what is registered:
`qdbus net.eksb.obsdc /`
Send signal:
`dbus-send --session --type=signal --dest=net.eksb.obsdc / net.eksb.Obsdc.Signal string:a`
Call method:
`dbus-send --session --type=method_call --print-reply --dest=net.eksb.obsdc / net.eksb.Obsdc.echo string:b`
`qdbus net.eksb.obsdc / net.eksb.Obsdc.echo hello`
*/

View File

@@ -0,0 +1,5 @@
package net.eksb.obsdc
interface Obs {
val handler:Handler
}

View File

@@ -0,0 +1,46 @@
package net.eksb.obsdc
import io.obswebsocket.community.client.OBSRemoteController
import org.slf4j.LoggerFactory
class ObsCommunity: Obs, AutoCloseable {
// TODO: make a single controller, and read ops from a queue.
override fun close() {}
override val handler: Handler = Handler { op ->
var controller:OBSRemoteController? = null
fun ready() {
controller?.let { controller ->
log.info("ready to send ${op}")
when(op) {
Op.STUDIO_TRANSITION -> {
controller.triggerStudioModeTransition { response ->
log.info("Response successful: ${response.isSuccessful}")
controller.disconnect()
}
}
}
}
}
controller = OBSRemoteController.builder()
.host("localhost")
.port(4455)
.password("R3tRkVXhFofJ2wRF") // TODO put this in a file
.autoConnect(true)
.lifecycle()
.onReady {
ready()
}
.and()
.build()
}
companion object {
private val log = LoggerFactory.getLogger(ObsCommunity::class.java)
}
}

View File

@@ -0,0 +1,6 @@
package net.eksb.obsdc
enum class Op {
STUDIO_TRANSITION,
;
}