3

I was using code from this answer to turn volume up and down for certain program (BS.player in this case), but I'm having problems when calling get_master_volume function. I'm using it inside pyHook's "OnKeyboardEvent", here's that part of code:

def get_master_volume():
    config.read('%s/config.cfg'%os.path.abspath(os.path.dirname(__file__)))
    proc = subprocess.Popen('%s sget Master '%config.get('main', input1), shell=True,    stdout=subprocess.PIPE) #config.get gives FULL and correct path to bsplayer.exe
    amixer_stdout = proc.communicate()[0].split('\n')[4]
    proc.wait()

    find_start = amixer_stdout.find('[') + 1
    find_end = amixer_stdout.find('%]', find_start)

    return float(amixer_stdout[find_start:find_end])

def set_master_volume(volume):
    config.read('%s/config.cfg'%os.path.abspath(os.path.dirname(__file__)))
    val = float(int(volume))

    proc = subprocess.Popen('%s sset Master '%config.get('main', input1) + str(val) +  '%', shell=True, stdout=subprocess.PIPE) #config.get gives FULL and correct path to bsplayer.exe
    proc.wait()

def OnKeyboardEvent(event):
    #nothing important
    if config.has_option('main', input1):
       set_master_volume(get_master_volume() - 1)
       print "New volume:", get_master_volume()

This is error:

File "c:/Users/Amar/Documents/volume+/main.py", line 53, in get_master_volume
     amixer_stdout = proc.communicate()[0].split('\n')[4]
IndexError: list index out of range

Can anyone explain me why this error fires and what's causing it (and what should I do to fix it)?

Best regards!

EDIT:

When I print proc.communicate() out I get this errors, what this means?

proc.communicate:'C:\Program' is not recognized as an internal or external comma
nd,
operable program or batch file.
('', None)

EDIT 2:

New error after I fixed bug in my config which was pointing on wrong bsplayer.exe path:

 Traceback (most recent call last):
 File "c:\Python27\lib\site-packages\pyHook\HookManager.py", line 351, in Keybo
 ardSwitch
 return func(event)
 File "c:/Users/Amar/Documents/volume+/main.py", line 101, in OnKeyboardEvent
  set_master_volume(get_master_volume() - 1)
 File "c:/Users/Amar/Documents/volume+/main.py", line 54, in get_master_volume
  amixer_stdout = proc.communicate()[0].split('\n')[4]
 File "c:\Python27\lib\subprocess.py", line 798, in communicate
  stdout = _eintr_retry_call(self.stdout.read)
 File "c:\Python27\lib\subprocess.py", line 478, in _eintr_retry_call
  return func(*args)
 ValueError: I/O operation on closed file
Community
  • 1
  • 1
Amar Kalabić
  • 888
  • 4
  • 15
  • 33
  • Either the list returned from `proc.communicate()` is empty, or list you get from splitting the string in the first index doesn't have five elements. You might want to split that line, see which part of that breaks. – thegrinner May 19 '14 at 19:27
  • 1
    You probably got fewer newlines than your expected. Omit the `[4]` index and change the design to handle this more gracefully (including raising a more specific exception if this is unexpected). – Brian Cain May 19 '14 at 19:28
  • @BrianCain I edited post with error I get when I try to print proc.communicate() out.. – Amar Kalabić May 19 '14 at 19:34
  • @thegrinner same message as above ... – Amar Kalabić May 19 '14 at 19:36
  • Can you post the lines you used to print out `proc.communicate()`? – thegrinner May 19 '14 at 19:36
  • @thegrinner just saw I made error with config which was causing it to give wrong path, now I get error I put in EDIT2.... – Amar Kalabić May 19 '14 at 19:41
  • @user3557637 For different problems, you should post different questions so that one answer can clearly associated with one problem. – glglgl May 19 '14 at 21:14
  • @glglgl Actually it's same problem :) that's just error when printing it out, so question remains.. – Amar Kalabić May 19 '14 at 21:34
  • @user3557637 Imagine you get one answer that deals about the `IndexError`, the other answer about the `I/O operation on closed file`. Which one are you going to accept? – glglgl May 19 '14 at 22:23
  • @glglgl Looks like you are right, my bad. I'll make another question tomorrow when I get up. Thanks! – Amar Kalabić May 19 '14 at 22:26
  • @user3557637 Maybe [my answer](http://stackoverflow.com/a/23748306/296974) helps you out; if you are stuck again, feel free to post a new question. – glglgl May 19 '14 at 22:39

2 Answers2

2

uuuuh… I just looked at the other question you're using and there's something you're totally missing. You're trying to use parameters sent to the linux program amixer with your windows program bsplayer.exe that has nothing related with the former. It is very unlikely to work! And it is the reason why it does not work. cf the other question:

proc = subprocess.Popen('/usr/bin/amixer sget Master', shell=True, stdout=subprocess.PIPE)

So the first part of the question is solving your problem in calling bsplayer.exe, but what you actually want it to do does not work.


you should try the following to call the subprocess:

proc = subprocess.Popen([config.get('main', input1), 'sget', 'Master'], stdout=subprocess.PIPE)

because, though I don't have much experience with windows' python, I think that calling it with the shell might not work as expected, try to interpret your path as arguments. Though maybe if you put quotes around the argument it may work:

proc = subprocess.Popen('"%s" sget Master '%config.get('main', input1), shell=True,    stdout=subprocess.PIPE)

what led me to that conclusion is that:

'C:\Program' is not recognized as an internal or external command,

usually means that the path to bsplayer.exe is being cut at the first space.


edit:

Could you run the following, and add the output to your question?

Basically:

  • I moved the proc.wait() before the communicate
  • moved the selection of the fourth line of output in a second step
  • added a print out of the list of the output

what I want to know is whether the error you're having is because of communicate() not working, or because you get less than four lines in the output.

So the following version is solving your calling problem:

def get_master_volume():
    config.read('%s/config.cfg'%os.path.abspath(os.path.dirname(__file__)))
    p = [config.get('main', input1), 'sget', 'Master']
    print("PROG:", p)
    proc = subprocess.Popen(p, stdout=subprocess.PIPE)

    proc.wait()

    amixer_stdout = proc.communicate()[0].split('\n')
    print("OUTPUT", amixer_stdout)
    amixer_stdout = amixer_stdout[4]

    find_start = amixer_stdout.find('[') + 1
    find_end = amixer_stdout.find('%]', find_start)

    return float(amixer_stdout[find_start:find_end])

though it outputs nothing.

Does your command actually work?! Did you actually try to do:

"C:\Program Files (x86)\Webteh\BSPlayer\bsplayer.exe" sget Master

in cmd to see if it works?

zmo
  • 24,463
  • 4
  • 54
  • 90
  • This is error for edited code: http://www.ipaste.eu/view?id=6697 Pastebin is not working so I put it here, it looks like every cloudflare server is heavily DDoSed – Amar Kalabić May 19 '14 at 20:22
  • First one: http://pastebin.com/6VgHntTh Second one: http://pastebin.com/6BJcKNfY btw. thanks for helping me with this! :) You are awesome! – Amar Kalabić May 19 '14 at 20:44
  • there was a typo in the codes, can you rerun the second one? – zmo May 19 '14 at 20:57
  • Hmmm, nothing comes back if I type it in... Looks like that's problem lol... http://pokit.org/get/img/c5b3ff57e9dd8e3cfb86f50a21d42178.jpg – Amar Kalabić May 19 '14 at 21:36
1

Let me try to answer these (actually) three questions you have.

  1. IndexError

    File "c:/Users/Amar/Documents/volume+/main.py", line 53, in get_master_volume
        amixer_stdout = proc.communicate()[0].split('\n')[4]
    IndexError: list index out of range
    

    This means that either the [0] access tries to access an empty sequence (unlikely), or that [4] tries to access a sequence which has a maximum of 4 entries, so that [4] does not exist.

    Obviously, the output has less than 4 lines, so proc.communicate()[0].split('\n') has no [4] entry.

    Either the program output doesn't match the expectations, or something else is wrong.

  2. proc.communicate

    proc.communicate:'C:\Program' is not recognized as an internal or external comma
    

    nd, operable program or batch file. ('', None)

    This seems to indicate that there is something wrong with your call's command line.

    config.get('main', input1) seems to contain the full path, which lies in C:\Program Files. So you should surround your program path properly with " (at the right level).

  3. I/O on closed file

    This third problem can be resolved by inspecting the call trace. Here we can see that there is something wrong with the way things are called: the communicate() call fails, as the stdout of the subprocess is already closed.

    It is unclear to me why this is the case; maybe you are calling communicate() twice? On the first call, it is closed, and as you attempt a second call, it fails as stdout has already been read out.

glglgl
  • 89,107
  • 13
  • 149
  • 217