Recent

Author Topic: [Solved] Tprocess, detach program, background, Omxplayer, UDP socket  (Read 2619 times)

chrnobel

  • Sr. Member
  • ****
  • Posts: 283
Hi.

I am trying to make an embedded video player on the Raspberry Pi, which I am going to start over the network.

Using Synapse, I can easily create a program that listens on a socket, and writes what is in the buffer like this:

Code: Pascal  [Select][+][-]
  1. var
  2.   x:integer;
  3.  
  4. procedure MulticastRecvTest;
  5. var
  6.   rcvsock:TUDPBlockSocket;
  7.   buf:string;
  8. begin
  9.   rcvsock:=TUDPBlockSocket.Create;
  10.   try
  11.     rcvsock.createsocket;
  12.     rcvsock.Bind('0.0.0.0','22401');
  13.     rcvsock.AddMulticast('224.0.0.100');
  14.     buf:=rcvsock.RecvPacket (60000);
  15.     writeln(buf);
  16.     writeln(DateTimeToTimeStamp(Now).Time);
  17.   finally
  18.     rcvsock.free;
  19.   end;
  20. end;
  21.  
  22. begin
  23.   for x:=1 to 10 do
  24.   MulticastRecvTest;
  25. end.      
  26.  

Works like a charm, loops ten times and output result if anything is send to the socket.

Then I want to combine it with this program, which can be run from commandline, and starts a omxplayer, showing the video, and detaches:

Code: Pascal  [Select][+][-]
  1. procedure runshow;
  2. var
  3.   AProcess: TProcess;
  4.  
  5. begin
  6.    AProcess := TProcess.Create(nil);  
  7.    try
  8.      AProcess.Executable:='omxplayer';
  9.      AProcess.Parameters.Add('/home/admin/videos/Engl.mov');
  10.      AProcess.Options := [];
  11.      AProcess.execute;
  12.    finally
  13.     Aprocess.free;
  14.    end;
  15. end;
  16.  
  17. begin
  18.   runshow;
  19. end.
  20.  
This also works as intended, executing the program (as root, due to Omxplayer, but this is no problem, as it is intended to work from startup) starts Omxplayer, and then detaches stdin as expected.

I still gets messages to stdout and stderr - this is a minor problem I have to find a solution to.

However my big problem is, if I try to combine those two program like this:

Code: Pascal  [Select][+][-]
  1. var
  2.   x:integer;
  3.  
  4. procedure MulticastRecvTest;
  5. var
  6.   rcvsock:TUDPBlockSocket;
  7.   AProcess: TProcess;
  8.   buf:string;
  9. begin
  10.   rcvsock:=TUDPBlockSocket.Create;
  11.   try
  12.     rcvsock.createsocket;
  13.     rcvsock.Bind('0.0.0.0','22401');
  14.     rcvsock.AddMulticast('224.0.0.100');
  15.     buf:=rcvsock.RecvPacket (60000);
  16.     if buf='start' then
  17.     begin
  18.       AProcess := TProcess.Create(nil);
  19.       try
  20.         AProcess.Executable:='omxplayer';
  21.         AProcess.Parameters.Add('/home/admin/videos/Engl.mov');
  22.         AProcess.Options := [];
  23.         AProcess.execute;
  24.       finally
  25.         Aprocess.free;
  26.       end;
  27.     end;
  28.   finally
  29.     rcvsock.free;
  30.   end;
  31. end;
  32.  
  33. begin
  34.   for x:=1 to 10 do
  35.   MulticastRecvTest;
  36. end.
  37.  

It does not detach the Omxplayer.

What am I doing wrong?
« Last Edit: October 04, 2019, 10:09:29 am by chrnobel »

Zaxxon

  • New Member
  • *
  • Posts: 30
Re: Tprocess, detach program, run in background, Omxplayer
« Reply #1 on: September 25, 2019, 01:33:40 pm »
what happens if you try
Code: Pascal  [Select][+][-]
  1.         AProcess.Executable:='nohup';
  2.         AProcess.Parameters.Add('omxplayer');
  3.         AProcess.Parameters.Add('/home/admin/videos/Engl.mov');
  4.         AProcess.Options := [];
  5.  

?

chrnobel

  • Sr. Member
  • ****
  • Posts: 283
Re: Tprocess, detach program, run in background, Omxplayer
« Reply #2 on: September 25, 2019, 05:11:56 pm »
what happens if you try
Code: Pascal  [Select][+][-]
  1.         AProcess.Executable:='nohup';
  2.         AProcess.Parameters.Add('omxplayer');
  3.         AProcess.Parameters.Add('/home/admin/videos/Engl.mov');
  4.         AProcess.Options := [];
  5.  

?
Tprocess can not do any piping, so starting piping omxplayer into nohup is not a solution as far as I understand.

However it gave me an idea, so  tried this instead:

Firstly I created a small script, that I was sure did piping and detaching as expected:
Code: Pascal  [Select][+][-]
  1. #!/bin/bash
  2. nohup omxplayer /home/admin/videos/Engl.mov < /dev/null > /dev/null 2>&1 &
  3. exit;

Then I tried with RunCommand instead of using TProcess, as it can handle scripts:
Code: Pascal  [Select][+][-]
  1. var
  2.   x:integer;
  3.   s:ansistring;
  4.  
  5. procedure MulticastRecvTest;
  6. var
  7.   rcvsock:TUDPBlockSocket;
  8.   buf:string;
  9. begin
  10.   rcvsock:=TUDPBlockSocket.Create;
  11.   try
  12.     rcvsock.createsocket;
  13.     rcvsock.Bind('0.0.0.0','22401');
  14.     rcvsock.AddMulticast('224.0.0.100');
  15.     buf:=rcvsock.RecvPacket (60000);
  16.     if buf='stop' then
  17.         fpsystem('killall -9 omxplayer.bin');
  18.     if buf='start' then
  19.         runcommand('/bin/bash',['scrstart','&'],s);    
  20.   finally
  21.     rcvsock.free;
  22.   end;
  23. end;
  24.  
  25. begin
  26.   for x:=1 to 10 do
  27.     MulticastRecvTest;
  28. end.
However, the result remains the same, the program do not detach as expected, and does not react to new commands (start/stop) send to it.

But if I removed the starting of an external process out of the socket try-finally loop, and executed that afterwards, then it works:
Code: Pascal  [Select][+][-]
  1. var
  2.   x:integer;
  3.   s:ansistring;
  4.  
  5. procedure MulticastRecvTest;
  6. var
  7.   rcvsock:TUDPBlockSocket;
  8.   buf:string;
  9. begin
  10.   rcvsock:=TUDPBlockSocket.Create;
  11.   try
  12.     rcvsock.createsocket;
  13.     rcvsock.Bind('0.0.0.0','22401');
  14.     rcvsock.AddMulticast('224.0.0.100');
  15.     buf:=rcvsock.RecvPacket (60000);
  16.   finally
  17.     rcvsock.free;
  18.   end;
  19.     if buf='stop' then
  20.         fpsystem('killall -9 omxplayer.bin');
  21.     if buf='start' then
  22.         runcommand('/bin/bash',['scrstart','&'],s);
  23. end;

Now I do only have one small issue, because even though I am able to detach the omxplayer from my program, and stdin, stdout, strerr is send to null, the program is still owner of omxplayer, so if I stop the program, it also stops the omxplayer.

This is a little bit odd?

Actually I do have two issues, but this a little OT, as I also would like to pipe keyboard commands like 'p' for pause into omxplayer - I can do that on Raspbian, but I use Alpine Linux, and for some strange reason it does not work there (neither do DBUS).
Alpine Linux is really good, but unfortunately there is no forum, which is a shame.

Zaxxon

  • New Member
  • *
  • Posts: 30
Re: Tprocess, detach program, run in background, Omxplayer
« Reply #3 on: September 25, 2019, 06:08:55 pm »
what happens if you try
Code: Pascal  [Select][+][-]
  1.         AProcess.Executable:='nohup';
  2.         AProcess.Parameters.Add('omxplayer');
  3.         AProcess.Parameters.Add('/home/admin/videos/Engl.mov');
  4.         AProcess.Options := [];
  5.  

?
Tprocess can not do any piping, so starting piping omxplayer into nohup is not a solution as far as I understand.

Are you sure?
I've used nohup to run vlc to open mp3 files, with tprocess. And that worked with no problem.


winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Tprocess, detach program, run in background, Omxplayer
« Reply #4 on: September 25, 2019, 06:15:07 pm »
If you set the right options it will work:


Code: Pascal  [Select][+][-]
  1. AProcess.Options := [poUsePipes]

Winni


chrnobel

  • Sr. Member
  • ****
  • Posts: 283
Re: Tprocess, detach program, run in background, Omxplayer
« Reply #5 on: September 29, 2019, 11:28:10 pm »
If you set the right options it will work:


Code: Pascal  [Select][+][-]
  1. AProcess.Options := [poUsePipes]

Winni
I will give it a try, maybe I can also control the pausing of the Omxplayer this way, as discussed in another thread, but I am not having to high expectations.

chrnobel

  • Sr. Member
  • ****
  • Posts: 283
Re: Tprocess, detach program, run in background, UDP socket
« Reply #6 on: October 04, 2019, 01:19:33 am »
This is really really strange.

First of all, I have made a simple shell script, just for testing purposes:

Code: Pascal  [Select][+][-]
  1. #!/bin/sh
  2. echo "start script"
  3. sleep 2
  4. echo "2"
  5. sleep 2
  6. echo "4"
  7. sleep 2
  8. echo "6"
  9. sleep 2
  10. echo "8"
  11. sleep 2
  12. echo "10"
  13. sleep 2
  14. echo "12"
  15. sleep 2
  16. echo "end script"
When executed from console, no problem, it counts for 14 seconds.

I can also call it from at small program, then I start the script by use of TProcess, here made with at loop that rapidly starts my script ten times, meaning ten running processes:
Code: Pascal  [Select][+][-]
  1. var
  2.   x:integer;
  3.  
  4. procedure waitforcall;
  5. var
  6.   AProcess: TProcess;
  7. begin
  8.   writeln('udp start');
  9.   AProcess := TProcess.Create(nil);  
  10.   try
  11.     AProcess.InheritHandles := False;
  12.     AProcess.Executable:='/bin/sh';
  13.     AProcess.Parameters.Add('-c');
  14.     Aprocess.Parameters.Add('./startshow');
  15.     AProcess.Options:=[];
  16.     AProcess.execute;
  17.   finally
  18.     Aprocess.free;
  19.   end;
  20.   writeln('udp end');
  21. end;
  22.  
  23. begin
  24.   for x:=1 to 10 do
  25.     waitforcall;
  26. end.
So far so good.

Then I want to control this via a multicast, so I created this UDP Multicast listener:
Code: Pascal  [Select][+][-]
  1. procedure waitforcall;
  2. var
  3.   rcvsock:TUDPBlockSocket;
  4.   buf:string;
  5.  
  6. begin
  7.   rcvsock:=TUDPBlockSocket.Create;
  8.   try
  9.     rcvsock.createsocket;
  10.     rcvsock.Bind('0.0.0.0','22401');
  11.     rcvsock.AddMulticast('239.66.16.10');
  12.     buf:=rcvsock.RecvPacket (60000);
  13.     if buf='startshow' then
  14.       writeln(buf);
  15.   finally
  16.     rcvsock.free;
  17.   end;
  18. end;
  19.  
  20. begin
  21.   while true do
  22.     waitforcall;
  23. end.
This also works totally as expected, as fast as I can send "startshow" telegrams over the UDP socket, is writes it on the screen.

However, if I combine the two program like this:
Code: Pascal  [Select][+][-]
  1. procedure waitforcall;
  2. var
  3.   rcvsock:TUDPBlockSocket;
  4.   buf:string;
  5.   AProcess: TProcess;
  6.  
  7. begin
  8.   rcvsock:=TUDPBlockSocket.Create;
  9.   try
  10.     rcvsock.createsocket;
  11.     rcvsock.Bind('0.0.0.0','22401');
  12.     rcvsock.AddMulticast('239.66.16.10');
  13.     buf:=rcvsock.RecvPacket (60000);
  14.     if buf='startshow' then
  15.     begin
  16.       writeln('udp start');
  17.       AProcess := TProcess.Create(nil);  
  18.       try
  19.         AProcess.InheritHandles := False;
  20.         AProcess.Executable:='/bin/sh';
  21.         AProcess.Parameters.Add('-c');
  22.         Aprocess.Parameters.Add('./startshow');
  23.         AProcess.Options:=[];
  24.         AProcess.execute;
  25.       finally
  26.         Aprocess.free;
  27.       end;
  28.       writeln('udp end');
  29.     end;
  30.   finally
  31.     rcvsock.free;
  32.   end;
  33. end;
  34.  
  35. begin
  36.   while true do
  37.     waitforcall;
  38. end.
Then the fun begins, because I would expect that for every time I send my UDP telegram, it should execute the startshow command, and start it as a new detached process - but no, it has to wait 14 seconds before it is ready for the next command.

And setting the recsock timeout to a lower value makes no difference (and using poUsePipes just sends the output from script into the blue, the problem remains the same, it takes 14 seconds).

The really, really odd thing is, that it actually outputs:

Udp start
Udp end
Script start
2
....
12
Script end

Which means that the script actually is detached, but still it blocks?

So why is it falling over its own feets?


winni

  • Hero Member
  • *****
  • Posts: 3197
Re: Tprocess, detach program, run in background, Omxplayer
« Reply #7 on: October 04, 2019, 01:34:40 am »
Hi!

I think Tprocess blocks 12 seconds.
Use TAsyncProcess instead.

Winni

chrnobel

  • Sr. Member
  • ****
  • Posts: 283
Re: Tprocess, detach program, run in background,
« Reply #8 on: October 04, 2019, 10:07:58 am »
I think Tprocess blocks 12 seconds.
No, as my read example show, it runs the procedure ten times without blocking

Quote
Use TAsyncProcess instead.

TAsyncProcess is a LCL component, and it have to be pure FPC.

BUT I have found out what the problem is - it is not legal / bad practice to nest try sentences.

So instead I moved the finally to right after buf have been filled, and then it works:
Code: Pascal  [Select][+][-]
  1. procedure waitforcall;
  2. var
  3.    rcvsock:TUDPBlockSocket;
  4.    buf:string;
  5.    AProcess: TProcess;
  6.    
  7. begin
  8.    rcvsock:=TUDPBlockSocket.Create;
  9.    try
  10.      rcvsock.createsocket;
  11.      rcvsock.Bind('0.0.0.0','22401');
  12.      rcvsock.AddMulticast('239.66.16.10');
  13.      buf:=rcvsock.RecvPacket (60000);
  14.   finally
  15.      rcvsock.free;
  16.   end;
  17.   if buf='startshow' then
  18.   begin
  19.      writeln('udp start');
  20.      AProcess := TProcess.Create(nil);  
  21.      try
  22.        AProcess.InheritHandles := False;
  23.        AProcess.Executable:='/bin/sh';
  24.        AProcess.Parameters.Add('-c');
  25.        Aprocess.Parameters.Add('./startshow');
  26.        AProcess.Options:=[];
  27.        AProcess.execute;
  28.      finally
  29.        Aprocess.free;
  30.      end;
  31.      writeln('udp end');
  32.   end;
  33. end;
  34.  

chrnobel

  • Sr. Member
  • ****
  • Posts: 283
Re: [Solved] Tprocess, detach program, background, Omxplayer, UDP socket
« Reply #9 on: October 07, 2019, 09:34:53 am »
I discovered that the above solution revealed another problem: a trail of defunct processes.

So I had to come up with another solution, and ended actually up (again) with fpsystem - but the important part is that the call is outside the try loop:

Code: Pascal  [Select][+][-]
  1. begin
  2.   rcvsock:=TUDPBlockSocket.Create;
  3.   try
  4.     rcvsock.createsocket;
  5.     rcvsock.Bind('0.0.0.0','22401');
  6.     rcvsock.AddMulticast('239.66.16.10');
  7.     buf:=rcvsock.RecvPacket (6000);
  8.   finally
  9.     rcvsock.free;
  10.   end;
  11.   if buf='startshow' then
  12.   fpsystem('/bin/sh ./startshow &');
  13.   if buf='pauseshow' then
  14.   fpsystem('/bin/sh ./pauseshow &');
  15. end;
  16.  

 

TinyPortal © 2005-2018