pythonscriptingobsobs-studio

OBS crashes when set_current_scene function called within a timer callback (Python scripting)


scenes = obs.obs_frontend_get_scenes()
def script_load(settings):
    obs.obs_frontend_add_event_callback(onevent)

def script_update(settings):
    global trigger, s_minutes, s_seconds, ending, e_minutes, e_seconds
    trigger = obs.obs_data_get_string(settings, "e_trigger scene")
    s_minutes = obs.obs_data_get_int(settings, "s_minutes")
    s_seconds = obs.obs_data_get_int(settings, "s_seconds")
    e_minutes = obs.obs_data_get_int(settings, "e_minutes")
    e_seconds = obs.obs_data_get_int(settings, "e_seconds")
    ending = obs.obs_data_get_string(settings, "s_ending scene")

def timer_callback():
    global tElapsed
    if state == 0:
        print("Error: State = 0")
        obs.remove_current_callback()
    if state == 1:
        tElapsed += 1
        print(tElapsed)
        if tElapsed == timer:
            tElapsed = 0
            set_scene()
            obs.remove_current_callback()
    if state == 2:
        tElapsed += 1
        print(tElapsed)
        if tElapsed == timer:
            tElapsed = 0
            obs.obs_frontend_streaming_stop()
            obs.remove_current_callback()

def set_scene():
    index = (obs.obs_frontend_get_scene_names()).index(ending)
    scene = scenes[index]
    obs.obs_frontend_set_current_scene(scene)

def onevent(event):
    global state, timer
    if event==obs.OBS_FRONTEND_EVENT_STREAMING_STOPPED:
        state = 0
    if event==obs.OBS_FRONTEND_EVENT_STREAMING_STARTED:
        state = 1
        timer = s_minutes * 60 + s_seconds
        obs.timer_add(timer_callback,1000)
    if event==obs.OBS_FRONTEND_EVENT_SCENE_CHANGED:
        if obs.obs_source_get_name(obs.obs_frontend_get_current_scene()) == trigger:
           state = 2
           timer = e_minutes * 60 + e_seconds
           obs.timer_add(timer_callback,1000)
        else:
            obs.timer_remove(timer_callback)
            if state == 1:
                print("Start timer stopped")
            elif state == 2:
                print("End timer stopped")

When I try to set the scene from within a timer callback function, OBS ends up crashing. I've tried to print the number for every time the callback function is called, and when I look at the logs, it shows every print function it's supposed to call, but it doesn't tell me why OBS crashed.

This is the code where I use a helper function to set the scene. With or without the helper function, it crashes either way. However, when I set the scene from outside the timer, everything works fine.

Any form of help is appreciated!


Solution

  • It's been a while since I worked on this script, but I have managed to fix the problem so I'll try my best to recall how I fixed it.

    Resolution

    It appears that the crash only occurs when the combination of the 3 functions (obs_frontend_add_event_callback(), timer_add() and obs_frontend_set_current_scene()) appears, so instead of using the frontend event callback, I used signal handlers instead.

    I first got the current scene and got the signal handler of that scene. Afterwards I connected a callback function which runs when the signal handler sends a "deactivate" signal. From there I added the timer callback which switches the scene when the timer reaches 0. This stopped the crashes from happening. My code for reference:

    current_scene = obs.obs_frontend_get_current_scene()
    current_handler = obs.obs_source_get_signal_handler(current_scene)
    obs.obs_source_release(current_scene)
    
    obs.signal_handler_connect(current_handler, "deactivate", checker)
    timer = s_minutes * 60 + s_seconds
    obs.timer_add(timer_callback, 1000)
    

    Notes:

    def script_load(settings):
        obs.obs_frontend_add_event_callback(onevent)
    
    def onevent(event):
        global output
        if event == obs.OBS_FRONTEND_EVENT_STREAMING_STARTED:
            stream = obs.obs_frontend_get_streaming_output()
            output = obs.obs_output_get_signal_handler(stream)
            obs.signal_handler_connect_global(output, frontevent)
            obs.obs_output_release(stream)
            obs.obs_frontend_remove_event_callback(onevent)
    

    References: