Как запустить python-osc внутри OBS как скрипт?

Я хочу/нужно запустить этот код внутри OBS как скрипт. Я взял этот OSC Sender для OBS, что он делает то, что название говорит: он отправляет сообщения OSC. Но внутри кода серверная часть закомментирована, потому что она не работает... прямо из коробки. Это необходимо для запуска OBS с LD_PRELOAD=/path/libpython3.7.so.

Я изменил код, но (раскомментированные строки), но при открытии сервера OBS остается непригодным для использования, заблокированным. Итак, я попробовал асинхронный сервер — параллельный режим python-osc. Я беру пример из его вики (что он работает в консоли ) и смешал с другим скриптом. Я сделал хороший код... но он делает что-то странное. Это код:

"""

"""
# osc data

import argparse
import random
import time
import math
import asyncio

from pythonosc import osc_message_builder
from pythonosc import udp_client

from pythonosc.dispatcher import Dispatcher
from pythonosc.osc_server import AsyncIOOSCUDPServer

client = None
server = None

#obs !
import obspython as obs
pleaseLog = False

host = None
serverPort = None
# transport = None

async def loop():
    """Example main loop that only runs for 10 iterations before finishing"""
    for i in range(10):
        print(f"Loop {i}")
        await asyncio.sleep(.5)

async def init_main():
    # global transport
    
    server = AsyncIOOSCUDPServer((host, serverPort), dispatcher, asyncio.get_event_loop())
    transport, protocol = await server.create_serve_endpoint()  # Create datagram endpoint and start serving
    
    await loop()  # Enter main loop of program
    transport.close()  # Clean up serve endpoint

def handleOSC(*args):
    for i in args:
        print(i)

# defines script description 
def script_description():
    return '''Send OSC data when source is activated if source name begins with /'''

# defines user properties
def script_properties():
    global props 
    props = obs.obs_properties_create()
    obs.obs_properties_add_text(props, "host", "Host IP", obs.OBS_TEXT_DEFAULT)
    obs.obs_properties_add_int(props, "clientPort", "Host port", 1, 400000, 1)
    obs.obs_properties_add_bool(props, "logOscOutput", "Log OSC output")
    obs.obs_properties_add_int(props, "serverPort", "Listen port", 1, 400000, 1)
    return props

def script_defaults(settings):
    obs.obs_data_set_default_string(settings, "host", "127.0.0.1")
    obs.obs_data_set_default_int(settings, "clientPort", 10000)
    obs.obs_data_set_default_int(settings, "serverPort", 10001)

def source_activated(cd):
    global pleaseLog
    source = obs.calldata_source(cd, "source")
    if source is not None:
        name = obs.obs_source_get_name(source)
        if name[0] == "/":
            client.send_message(name, 1)
            if (pleaseLog):
                print("send " + name)

def script_load(settings):
    global dispatcher
    global host
    
    sh = obs.obs_get_signal_handler()
    obs.signal_handler_connect(sh, "source_activate", source_activated)

    dispatcher = Dispatcher()
    dispatcher.map("/*", handleOSC)

# def script_unload():
#   global transport
#   print(f'script_unload(settings)')
#   transport.close()  # Clean up serve endpoint

def script_update(settings):
    global host
    global client
    global server
    global clientPort
    global serverPort
    global pleaseLog

    pleaseLog = obs.obs_data_get_bool(settings, "logOscOutput")
    host = obs.obs_data_get_string(settings, "host")
    clientPort = obs.obs_data_get_int(settings, "clientPort")
    serverPort = obs.obs_data_get_int(settings, "serverPort")
    
    # Client
    client = udp_client.SimpleUDPClient(host, clientPort)
    print("target set to "+host+":"+str(clientPort)+"")
    
    # Server
    print("serving in "+host+":"+str(serverPort)+"")
    asyncio.run(init_main())

Я не программист, поэтому асинцио для меня беспорядок. Я этого не понимаю. Но я знаю, что он делает и что я хотел бы, чтобы он делал.

Когда скрипт загружается (в script_update(settings)), он открывает сервер и запускает функцию loop(). Эта функция представляет собой 5-секундный цикл, который печатает некоторый текст. Если я подключусь к правильному порту из PureData и отправлю несколько сообщений OSC, эти сообщения поступят в OBS... но все они будут удалены вместе, когда цикл завершится. При этом ничего нет, OBS заблокирован и в Script Log ничего нет.

Если я запускаю пример кода python-osc asyncio в консоли, пока выполняется цикл, приходят каждые Loop 0, Loop 1 и т. д., и каждое сообщение, и все они печатаются в нужное время.

Как мне заставить этот код работать? Мне нужно открыть этот сервер и одновременно запустить гораздо больше кода. Я использую OBS как игровой движок.


person Mario Mey    schedule 11.01.2021    source источник


Ответы (1)


Наконец, я не использовал Asyncio. Вместо этого я использую метод Blocking Server, но внутри функции threading.Thread(). На данный момент это работает именно так.

Важно закрывать порт при выгрузке или перезагрузке скрипта.

В этом мне помогли Oro, Treblig_Punisher (пользователи из OBS Discor).

"""

"""
# osc data

import argparse, random, time, math, threading

from pythonosc import osc_message_builder
from pythonosc import udp_client

from pythonosc import dispatcher
from pythonosc import osc_server

targetIp = "127.0.0.1"
targetPort = 10000
serverPort = 10008

client = None
server = None

#obs !

import obspython as obs
pleaseLog = False

def handleOSC(address, args, data):
    print (address)
    print (args)
    print (data)

# defines script description 
def script_description():
    return '''Send and receive OSC messages'''

# defines user properties
def script_properties():
    #global props 
    props = obs.obs_properties_create()
    obs.obs_properties_add_text(props, "host", "Host IP", obs.OBS_TEXT_DEFAULT)
    obs.obs_properties_add_int(props, "port", "Host port", 1, 400000, 1)
    obs.obs_properties_add_bool(props, "logOscOutput", "Log OSC output")
    obs.obs_properties_add_int(props, "serverPort", "Listen port", 1, 400000, 1)
    return props

def script_defaults(settings):
    obs.obs_data_set_default_string(settings, "host", targetIp)
    obs.obs_data_set_default_int(settings, "port", targetPort)
    obs.obs_data_set_default_int(settings, "serverPort", serverPort)

# Cuando se activa un source
def source_activated(cd):
    global pleaseLog
    source = obs.calldata_source(cd, "source")
    if source is not None:
        name = obs.obs_source_get_name(source)
        
        current_scene = obs.obs_scene_from_source(obs.obs_frontend_get_current_scene())
        scene_item = obs.obs_scene_find_source(current_scene, name)
        boolean = obs.obs_sceneitem_visible(scene_item)
        
        print(boolean)
        if name[0] == "/":
            client.send_message(name, boolean)
            if (pleaseLog):
                print("send " + name + boolean)

def script_load(settings):
    global despachante
    
    sh = obs.obs_get_signal_handler()
    obs.signal_handler_connect(sh, "source_activate", source_activated)

    despachante = dispatcher.Dispatcher()
    despachante.map("/*", handleOSC)

def script_unload():
    global server
    server.server_close()

def script_update(settings):
    global host
    global port
    global client
    global server
    global pleaseLog

    pleaseLog = obs.obs_data_get_bool(settings, "logOscOutput")
    host = obs.obs_data_get_string(settings, "host")
    port = obs.obs_data_get_int(settings, "port")

    # Client
    client = udp_client.SimpleUDPClient(host, port)
    print("target set to "+host+":"+str(port)+"")

    # Server
    serverPort = obs.obs_data_get_int(settings, "serverPort")
    try:
        server.server_close()
    except:
        print('*Server aun no creado')
        # raise
    server = osc_server.BlockingOSCUDPServer(("127.0.0.1", serverPort), despachante)
    t = threading.Thread(target=server_th, args=([settings]))
    t.daemon = True
    t.start()

    # Loop every 1000ms
    # obs.timer_remove(funcion_loop)
    # if and source_name != "":
        # obs.timer_add(funcion_loop, 1000)

# Threading function
def server_th(settings):
    print(f'Serving on {server.server_address}')
    server.serve_forever()  # Blocks forever
person Mario Mey    schedule 16.01.2021