Python Forum
Echo call to VLC bash using subprocess.Popen on Linux
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Echo call to VLC bash using subprocess.Popen on Linux
#1
I am using this both on my macosx and linux and it works well.
On linux the shell commands are slightly different:

vlc -I oldrc --rc-unix=/home/user/Documents/Sockets/socket1.sock
vlc -I oldrc --rc-unix=/home/user/Documents/Sockets/socket2.sock

and

echo play | nc -U /home/user/Documents/Sockets/socket1.sock
echo enqueue /home/user/Documents/DualscreenVLC/videos/MVI_2534.MP4 | nc -U /home/user/Documents/Sockets/socket1.sock

I am attempting to use subprocess.Popen in Python for further control but here I run into difficulties on Linux (Ubuntu). It either hangs on the stdout.read() call or when I take this away, all the shell commands are only executed after the script finishes and I get a broken pipe error. The issue seems to be specifically with the 'echo' commands. Did I migrate wrong?
This is the python script:

import subprocess
import time

Socket1Location = "/Users/user/socket1.sock"
Socket2Location = "/Users/user/socket2.sock"
video1 = "/Users/user/Documents/Scripts/DualscreenVLC/videos/video01.mp4"
video2 = "/Users/user/Documents/Scripts/DualscreenVLC/videos/video02.mp4"

def RunVLCCommand1(cmd):
    p = subprocess.Popen("echo " + cmd + " | nc -U " + Socket1Location, shell = True, stdout = subprocess.PIPE)
    errcode = p.wait()
    retval = p.stdout.read()
    print "returning: " + retval
    return retval
    
def RunVLCCommand2(cmd):
    p = subprocess.Popen("echo " + cmd + " | nc -U " + Socket2Location, shell = True, stdout = subprocess.PIPE)
    errcode = p.wait()
    retval = p.stdout.read()
    print "returning: " + retval
    return retval

subprocess.Popen(["/Applications/VLC.app/Contents/MacOS/VLC","--rc-unix=/Users/user/socket1.sock"])
subprocess.Popen(["/Applications/VLC.app/Contents/MacOS/VLC","--rc-unix=/Users/user/socket2.sock"])

#RunVLCCommand1 and 2 can now be used to send commands to VLC, for example RunVLCCommand1('play')
Reply
#2
Hi, try this perhaps
p = subprocess.run("echo " + cmd + " | nc -U " + Socket1Location, shell = True, capture_output=True)
print(p.returncode)
print(p.stdout)
Reply
#3
Thank you, I tried it but I get an "attribute error: 'module' object has no attribute 'run'.
Should I call another library?
Reply
#4
subprocess.run() is new in python 3.5. Can you upgrade to this version? Hmm. Actually, the capture_output parameter is new in 3.7. You could perhaps simply use the communicate() method.i
p = subprocess.Popen("echo " + cmd + " | nc -U " + Socket1Location, shell = True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
Reply
#5
When I use communicate() the script hangs, just like when I use stdout.read()...
This is the script:

p = subprocess.Popen(['vlc -I oldrc --rc-unix=/home/user/Documents/Sockets/socket1.sock'], shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
out, err = p.communicate()

p = subprocess.Popen(['echo enqueue /home/user/Documents/DualscreenVLC/videos/MVI_2534.MP4 } nc -U /home/user/Documents/Sockets/socket1.sock'], shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
out, err = p.communicate()
I can try upgrading to python 3.5 tomorrow but it maybe it is related to the operating system as I am not finding this issue anywhere else...
Reply
#6
There is an old code that I used in Linux for certain cases when stdout blocks with subprocess. It uses socketpair() and select(). Here is an example involving two scripts a.py and b.py (launched by a.py which reads its output), but it also works when the second process is not a python program. I already posted this in other forums but I think it's a nice trick to know
##################################
# a.py

import subprocess
import socket
import select

esock, echildsock = socket.socketpair()
osock, ochildsock = socket.socketpair()
p = subprocess.Popen(['python3','b.py'], 
    stderr=echildsock.fileno(),
    stdout=ochildsock.fileno())

while p.poll() is None:
    r, w, x = select.select([esock, osock],[],[], 1.0)
    if not r:
        continue # timed out
    for s in r:
        print('stdout ready' if s is osock else 'stderr ready')
        data = s.recv(1024)
        print('received', data.decode('utf8'))
osock.shutdown(socket.SHUT_RDWR)
osock.close()
esock.shutdown(socket.SHUT_RDWR)
esock.close()
##################################
# b.py

res = input('???')
print('in b:', res)
Reply
#7
Thank you, that looks great.

If I understand it well, I can replace asock and osock with the vlc socket locations.
And I can add the echo commands to the input in b.py so it will be send to both sockets?
Does for s in r: mean that the p.poll() command iterates through b.py?
Reply
#8
Quote:If I understand it well, I can replace asock and osock with the vlc socket locations.

No, only replace the call to Popen() at line 10-12 with your command:
p = subprocess.Popen("echo " + cmd + " | nc -U " + Socket1Location,
    shell = True, 
    stderr=echildsock.fileno(),
    stdout=ochildsock.fileno())
Quote:Does for s in r: mean that the p.poll() command iterates through b.py?
No while p.poll() is None iterates while the process p is running. Perhaps you don't know the select command. The call to select() blocks until there is something to read in the sockets esock or osock which are connected to p's error and output streams. It returns a list of sockets that are ready, so r can be [esock] or [osock] or [esock, osock]. The for s in r reads the data from the sockets that have something to receive. I added a timeout of 1 second in select() so that every one second, if there is nothing to read, a.py checks if process p is still alive.
Reply
#9
Thank you very much, that makes sense.
I have been trying to implement it but without the shell=true flag I get this error:
OSError: [Errno 2] No such file or directory
When I split the command into:
(['vlc','-I oldrc --rc-unix=/home/user/Documents/Sockets/socket1.sock'],stderr=echildsock.fileno(), stdout=ochildsock.fileno())
The error is mitigated but no socket is opened. (I tried every combination of splitting the command).

When I do add the shell=True command the code hangs at the stdout again except when I add a 'break' to the while loop. An instance of VLC loads but the echo calls don't seem to communicate with vlc.
Reply
#10
You could perhaps simply remove the echo command and write directly to the nc command stdin
p = subprocess.Popen(["nc", "-U ", Socket1Location], stdin = subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, err = p.communicate(input=b'play')
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Is possible to run the python command to call python script on linux? cuten222 6 734 Jan-30-2024, 09:05 PM
Last Post: DeaD_EyE
Information subprocess.Popen() suddenly giving me grief? davecotter 3 626 Dec-13-2023, 10:49 PM
Last Post: davecotter
  I'm trying to make my Alexa/Echo dot 3 powered by ChatGPT.... mariozio 1 1,010 Apr-20-2023, 05:24 PM
Last Post: farshid
  Use subprocess.Popen and time.sleep chucky831 2 1,955 Aug-11-2022, 07:53 PM
Last Post: carecavoador
  Call a bash script from within a Python programme Pedroski55 6 2,473 Dec-06-2021, 01:53 PM
Last Post: DeaD_EyE
  use subprocess on linux\pi wwith a "grep " command korenron 2 8,116 Oct-19-2021, 10:52 AM
Last Post: DeaD_EyE
  continue if 'subprocess.call' failes tester_V 11 5,176 Aug-26-2021, 12:16 AM
Last Post: tester_V
  printing out the contents aftre subprocess.call() Rakshan 3 2,761 Jul-30-2021, 08:27 AM
Last Post: DeaD_EyE
  Subprocess.Popen() not working when reading file path from csv file herwin 13 15,113 May-07-2021, 03:26 PM
Last Post: herwin
  Did subprocess.Popen() causes main routine to pause stdout? liudr 4 3,656 May-04-2021, 08:58 PM
Last Post: liudr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020