Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
belltown
Level 7

Scene Graph Screensaver Tasks not Terminating

I have a Scene Graph channel with a Scene Graph private screensaver. The screensaver uses a Task node, which gets started when the screensaver starts. I would expect that each time the screensaver exits, the Task thread would terminate, to be started anew the next time the screensaver runs. However, the screensaver Task thread does not terminate when the screensaver exits. Consequently, each time the screensaver runs, a new Task thread is spawned, and ALL Task threads from prior invocations of the screensaver continue to run simultaneously.

Is this a bug, or am I doing something wrong??? I'm using a Roku 2XS, Model 3100X, Software version 7.5.0 • build 4099-02.

Here's some code that demonstrates the problem. Run the channel, wait for the screensaver to activate, then exit the screensaver back to the main thread. Repeat several times. Observe output from multiple instances of the Task node in the debug console.

components/MainScene.xml
<?xml version="1.0" encoding="UTF-8"?>

<component name="MainScene" extends="Scene">
  <children>
    <Label
      id="label"
      text="Hello, World!"
      color="0x0000ffff"
      width="1280"
      height="720"
      horizAlign="center"
      vertAlign="center" />
  </children>
  <script type="text/brightscript" >
    <![CDATA[
      sub init()
        label = m.top.findNode("label")
        label.font = "font:LargeSystemFont"
        label.font.size = 150
      end sub
    ]]>
  </script>
</component>


components/Screensaver.xml
<?xml version="1.0" encoding="UTF-8"?>

<component name="Screensaver" extends="Scene">
  <children>
    <Label
      id="label"
      text="Screensaver!"
      color="0x00ffffff"
      width="1280"
      height="720"
      horizAlign="center"
      vertAlign="center" />
    <TaskScreensaver id="taskScreensaver" control="RUN" />
  </children>
  <script type="text/brightscript" >
    <![CDATA[
      sub init()
        label = m.top.findNode("label")
        label.font = "font:LargeSystemFont"
        label.font.size = 150
      end sub
    ]]>
  </script>
</component>


components/TaskScreensaver.xml

<?xml version="1.0" encoding="UTF-8"?>

<component name="TaskScreensaver" extends="Task">
  <script type="text/brightscript" >
    <![CDATA[
      sub init()
        m.top.functionName = "taskRun"
      end sub

      sub taskRun()
        taskId = CreateObject("roDateTime").ToISOString()
        port = CreateObject("roMessagePort")
        while true
          Wait(5000, port)
          print taskId
        end while
      end sub
    ]]>
  </script>
</component>


source/Main.brs
sub Main()
    screen = CreateObject("roSGScreen")
    scene = screen.createScene("MainScene")
    port = CreateObject("roMessagePort")
    screen.SetMessagePort(port)
    screen.Show()
    while true
        msg = Wait(0, port)
        if Type(msg) = "roSGScreenEvent"
            if msg.IsScreenClosed()
                exit while
            end if
        end if
    end while
end sub


source/Screensaver.brs
sub RunScreenSaver()
    screen = CreateObject("roSGScreen")
    port = CreateObject("roMessagePort")
    screen.SetMessagePort(port)
    scene = screen.CreateScene("Screensaver")
    screen.Show()
    while true
        msg = Wait(0, port)
        if Type(msg) = "roSGScreenEvent"
            if msg.IsScreenClosed()
                exit while
            end if
        end if
    end while
end sub


manifest

title=Screensaver Task Test
major_version=1
minor_version=0
build_version=0
mm_icon_focus_hd=pkg:/images/FocusHD-540x405.png
splash_screen_fhd=pkg:/images/SplashFHD-1920x1080.png
screensaver_title=Screensaver
screensaver_private=1
ui_resolutions=hd
https://github.com/belltown/
0 Kudos
4 Replies
EnTerr
Level 8

Re: Scene Graph Screensaver Tasks not Terminating

Let me see if i understand the exact thing reported.
So you are making a private ("owned" my be a better word) SS, which engages during the proper app run - and when awoken, the SS main and rendition threads are shut down but that tasks remain?

What happens when you exit the channel - are the tasks truly immortal?
If not, i am not sure if that qualifies as a proper bug. Feature, sure. Tasks are "headless" (no UI), so they could as well keep running.

PS. a bit on the side, i feel uneasy about this
   <TaskScreensaver id="taskScreensaver" control="RUN" />

i mean it's cute but i have vague feeling i might have seen a proscription somewhere to not do things like that (get dynamic while "Xmlotron" is still assembling). To me it would be preferable to start the task explicitly in the initializer, for reasons of readability and also not to think about order of initialization - parent v. children v. fields v. scripts - at least i know the initializer is called after everything has been constructed.
0 Kudos
belltown
Level 7

Re: Scene Graph Screensaver Tasks not Terminating

I think your understanding is correct. When the screensaver terminates, its main and render threads terminate, but the task it started continues on. The task is a child of the screensaver's Scene node. I would expect that when a scene terminates, whether the main scene or a screensaver scene, then any running child task of that scene should also be terminated. I'd terminate them myself, although I can't because there's no way I know of to act upon a screensaver's exiting.

Yes, when the channel itself terminates back to the Home screen (if I press the Home key), it appears that all tasks (main scene-created and screensaver-created) terminate.

Separate issue: There was a point in my development when I was able to get the main thread to exit, leaving the screensaver running. I would have though that closing the scene and exiting Main() would also have terminated the screensaver, but that wasn't the case; as a workaround, I had to send a Home keypress ECP command to ensure both the main and screensaver threads were shut down in cases where I was exiting the channel without the user pressing the Home key.

Setting control="RUN" in the Task Xml file isn't something I do in my actual code. I was just trying to simplify things in my test example code. I've checked and it makes no difference when I start the task.
https://github.com/belltown/
0 Kudos
EnTerr
Level 8

Re: Scene Graph Screensaver Tasks not Terminating

"belltown" wrote:
The task is a child of the screensaver's Scene node. I would expect that when a scene terminates, whether the main scene or a screensaver scene, then any running child task of that scene should also be terminated.

Ah, you would think so, won't you!
Things might not be quite as they seem. I am a bit dusty but if i recollect the <Task/> node is just a template for a thread - when you trigger it to run, a new thread is spun off and gets the original `m` of the component, which it is left with a clone of `m` (i.e. all fun parts stripped). And since then the thread task that's running is unrelated to the <Task/> node that may be in RSG. You can repetitively spin off new threads, keeping in mind `m` will be robbed every time.

Separate issue: There was a point in my development when I was able to get the main thread to exit, leaving the screensaver running. I would have though that closing the scene and exiting Main() would also have terminated the screensaver, but that wasn't the case; as a workaround, I had to ...

Eh, i can take it or leave it. I mean RunScreenSaver() and RunUserInterface() are supposed to be sandboxed/isolated from each other. I remember back in the day RokuMarkN did a review on how it's ok for the two to interact with each other and the conclusion was being transactional in tmp:/. So one of the "processes" (rendition threads) surviving independently from the other does not shock me.
0 Kudos
belltown
Level 7

Re: Scene Graph Screensaver Tasks not Terminating

I guess the moral of the story is to not use continuously-running Task threads in a screensaver. Instead, create a separate thread to handle a single asynchronous operation at a time then terminate.

My workaround is to change my design slightly so I now have a repeating Timer node in my screensaver scene. Each time the Timer fires, I set the Task node's control field to "RUN". It seems like this creates a separate task thread each time, which terminates after handling the request. Now I don't have to worry about lingering threads that won't go away each time the screensaver exits.

I'm still not clear about all this "m" stuff you were talking about. I'm sure it will click eventually; I feel like I'm getting closer to understanding it. All my Tasks are quite straightforward. The only use they have for "m" is to access the interface fields.

And yes, I get what you're saying about separating RunUserInterface from RunScreensaver, which might explain why closing the main scene doesn't automatically close the screensaver, why it's necessary to emit a Home keypress (twice) to kill them both. And I am using that exact same tmp:/ method you referred to for communication between my Main scene and the screensaver. What my Task is for is to read the tmp:/ file every few seconds for changes.

Anyway, I have it working the way I want now.

Thanks for your insight.
https://github.com/belltown/
0 Kudos