1

Ok, I am running Ubuntu 15.04 with Kodi 15.2 as an HTPC. I have always had problems with suspend and hibernate due to the fact that it appears that the two systems' power management cause some conflicts. I have had Ubuntu put my system to sleep while watching movies on Kodi, so I disabled the power management. I have had Kodi put my system to sleep while watching Netflix (either with Advanced Launcher or Chrome Launcher), so I disabled that (currently my HTPC runs 24/7). I am trying to come up with some sort of script that not only measures inactivity, but audio output as well. I am a total noob when it comes to scripting, but this is what I came up with so far:

    LOG=/var/log/sleepcounter.log
    sound=0 > /var/log/sleepcounter.log

    while true: do
        sleep 1

        # check if sound is sent to speakers, add 1 if not
        if pactl list | grep -v RUNNING > /dev/null; then
            echo sound=$((sound += 1)) > /var/log/sleepcounter.log;
        fi
    done

This essentially counts seconds that audio is not playing. The problem then is it does not reset the counter to "0" when audio does play. I attempted to switch it around, and came up with a slightly different script that does NOT work:

    LOG=/var/log/sleepcounter.log
    sound=0 > /var/log/sleepcounter.log
    read -d $'\x04' sound < "$LOG"


    while true; do
            sleep 1

            # check if sound is sent to speakers, add 1 if not
            if pactl list | grep  RUNNING > /dev/null; then
                    echo sound=0 > /var/log/sleepcounter.log
            else echo sound=$((sound += 1)) > /var/log/sleepcounter.log;

            fi
    done

This exact script does not write anything to the sleepcounter.log file, when I check it it's blank. I can't figure out how to make it default to sound=0 and maintain 0 while sound is playing, start counting when sound stops, followed by starting over from 0 when sound starts again...

I have this paired up with another script:

    LOG=/var/log/sleepcounter.log
    read -d $'\x04' sound < $LOG

    while true; do
            sleep 30
            # check if there is any system activity
            if [[ `xprintidle` > 600000 && "$sound" -ge 600 ]]; then
                    (sudo pm-suspend-hybrid);
            fi
    done

This one does work. If I manually set sleepcounter.log to sound=600 (or more) it puts the system to sleep when it has been inactive for 10 minutes. While this works, I am thinking there also might be a way to combine the two scripts into one, just to make it a bit simpler.

I know I am having a problem with referencing the variables, and this is my first time trying to write a script. If anyone could help me out, I would greatly appreciate it.

1

With a little bit of testing here I saw Kodi close its client to Pulseaudio after a couple of minutes of idling. That makes this problem quite simple. In your shutdown script all you need to test for (other than time) is that there's no Kodi or Chrome clients. That's as simple as:

DISPLAY=:0 pactl list clients | grep -E 'kodi|chrome'

Edit: I honestly hadn't read past the title before writing this answer. Setting the DISPLAY seems to be the critical element, at least here, to get pactl looking at the right Pulseaudio session.

If you're scripting this into something remember that grep returns 0 on a match. And you can use the -q argument instead of redirecting to /dev/null.

However if you have navigation sounds turned off too, the user might just be in a menu. You might want to do another sort of check, perhaps hooking into input or checking the average screen colour (set the screensaver to black screen, if screen is black, and there's no sound, suspend).

4
  • I haven't tried this yet, but doesn't Kodi get "suspended" in a way when using Chrome Launcher? If you're not familiar with Chrome Launcher, it minimizes the Kodi interface and launches Chrome from the Ubuntu desktop. When I exit Chrome (alt+F4) it goes right back into Kodi with the screensaver active (I have that set to 50% dim). When I run pactl list | grep RUNNING it shows RUNNING whether I am in Chrome or Kodi, as long as audio is playing. – Bighairyg Dec 11 '15 at 21:28
  • I see why you're having so many problems now (refer you back to me not reading). Yes. Yes it would. But there's nothing to stop you expanding the grep to chrome as well. If Kodi or Chrome (or whatever) are making noise, don't suspend. If they aren't do other checks and if they pass, suspend. – Oli Dec 11 '15 at 22:20
  • Chrome will hang on indefinitely, as long as it's alive. – Oli Dec 11 '15 at 22:25
  • Every time I checked, running the command pactl list | grep RUNNING it looked like Chrome released it after about 30 seconds. Thanks for your assistance, but I decided to go a different route, which I posted below. – Bighairyg Dec 20 '15 at 20:36
1

I will post this here for anyone else looking for a simple solution. My biggest concern is many times we fall asleep watching movies, and wake up to the TV still being 'on'. I am new to Linux, and our previous system was Windows XP (without Kodi), so having the screen disabled after 10 minutes was no problem (although it would occasionally glitch, and shut off in the middle of a Netflix movie). I have had two different Dell systems with Windows die in the past by going to sleep and never waking up, so I never used the sleep/suspend functions built in to Windows. I think Kodi is an awesome interface, much better than trying to control the Windows desktop with a wireless mini keyboard/trackpad.

I finally figured this out, and of course I was making it WAY more complicated than it really is. What I ended up doing was rewriting the two different scripts into a single one:

    while true; do
            sleep 1     # wait for 1 second to continue loop

            # check for sound output, if yes clear variable, if no then count +1
            if pactl list | grep RUNNING > /dev/null; then
                unset sound; echo $sound; else
                echo sound=$((sound++))
            fi

            # check idle time and no-sound time, if yes then suspend and exit loop
            if [[ `xprintidle` > 600000000 && "$sound" -ge 600 ]]; then
                (sudo pm-suspend); exit 0
            fi
    done

After saving the script, I then had to perform some other commands to make it work properly:

    chmod x+ /path/to/filename.sh #to make it executable
    chmod 555 /path/to/filename.sh #had a problem with permissions and ownership

followed by modifying the /etc/sudoers file to be able to call pm-suspend without being root or asking for a password by adding this to the end of the file:

    username  ALL = NOPASSWD: /usr/sbin/pm-hibernate
    username  ALL = NOPASSWD: /usr/sbin/pm-suspend

replacing username with the actual username I use to log into my system.

So far, regardless of what is producing sound (I tested with Netflix via Chrome Launcher through Kodi, YouTube in Chrome straight off the desktop, and playing a movie directly from Kodi) it suspends approximately 10 minutes after the sound stops, as long as I am not doing anything else. I say "approximately" because I believe xprintidle throws off some random numbers here and there, but so far it ALWAYS sleeps. I had to add the exit command, otherwise it generated a sleep/wake loop that was hard to get out of. I then added the script to be run at startup by adding a cron job with @reboot /path/to/filename.sh. This works great, but I am not sure yet if cron restarts on resume (I don't believe it does, haven't been able to test that yet), or if I have to call the script from somewhere else when the system wakes up.

I assume I need to ask in another thread, but my next part of this project is to make sure this script starts again upon resume, and to make the system recognize my Rii Mini i28 wireless keyboard (with USB dongle) as a wake-up device.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.