You are not logged in.

#1 2012-09-05 14:25:31

takanuva
Member
Registered: 2009-04-19
Posts: 4

Run a script when mpd wants to play a song

Hi,

I have built a power strip I can control through USB. Now I have teach my computer how to turn on or off a plug , I would like that it turns on automatically  my speakers when my computer play a song and turns it off when it stops.
As the music is controlled by mpd, I would like to know if it is possible to add this functionality to mpd? Or do I have to tell Alsa to make this work (how?)? Or do I have to make a daemon which will check whether a song is played or not?

Thanks

Offline

#2 2012-09-06 12:51:47

SahibBommelig
Member
From: Germany
Registered: 2010-05-28
Posts: 80

Re: Run a script when mpd wants to play a song

You would write a simple mpd client for such a task usually. (not sure if perhaps 'mpc' has this built-in already)

Example C-program using libmpdclient that wakes up once mpd plays a song or stops playing:

/*
 * Compile: gcc mpdsonglisten.c -o mpdsonglisten -lmpdclient -std=c99 
 * Run: ./mpdsonglisten localhost 6600 <on_play_script> <on_stop_script>
* Example: ./mpdsong localhost 6600 'echo plays!' 'echo stopped!'
* 
* It will call on_play_script once mpd starts playing,
* and on_stop_script once it pauses, stops or does something unknown.
*
* Error handling is done by ignoring none-fatal erros and trying to reconnect if
* fatal errors happen.
 * */
#include <mpd/client.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
 
static volatile bool not_ctrlc_pressed = true;
 
 
static bool check_error(struct mpd_connection * client)
{
    if(mpd_connection_get_error(client) != MPD_ERROR_SUCCESS) {
        printf("Error: %s (Retry in 1 second...)\n", mpd_connection_get_error_message(client));
        if(!mpd_connection_clear_error(client)) {
            mpd_connection_free(client);
            sleep(1);
            return true;
        }
    }
    return (client == NULL);
}
 
static struct mpd_connection * connect(const char * host, unsigned port) 
{
    struct mpd_connection * client = NULL;
    for(;;) {
        client = mpd_connection_new(host, port, 2000);
        if(check_error(client)) {
            continue;
        }
 
        break;
    }
 
    return client;
}
 
void cancel_signal(int signal)
{
    if(signal == SIGINT) {
        not_ctrlc_pressed = false;
    }
}
 
int main(int argc, char const *argv[])
{
    if (argc < 3) {
        printf("Usage: prog <hostname> <port>");
        return EXIT_FAILURE;
    }
 
    int previous_sond_id = -1;
    enum mpd_state prev_state = MPD_STATE_UNKNOWN;
    struct mpd_connection * client = connect(argv[1], strtol(argv[2], NULL, 10));
 
    signal(SIGINT, cancel_signal);
 
    while(not_ctrlc_pressed) {
        enum mpd_idle events = mpd_run_idle (client);
        if(check_error(client)) {
            client = connect(argv[1], strtol(argv[2], NULL, 10));
            continue;
        }
 
        if (events & MPD_IDLE_PLAYER) {
            struct mpd_status * status = mpd_run_status(client);
            if (status != NULL) {
                enum mpd_state play_state = mpd_status_get_state(status);
                int current_song_id = mpd_status_get_song_id(status);
 
                switch(play_state) {
                    case MPD_STATE_PLAY:
                        if (current_song_id != previous_sond_id && prev_state != play_state) {
                            previous_sond_id = current_song_id;
                            if (argc > 3)
                                system(argv[3]);
                        }
                        break;
                    case MPD_STATE_UNKNOWN:
                    case MPD_STATE_PAUSE:
                    case MPD_STATE_STOP:
                        previous_sond_id = -1;
                        if (argc > 4)
                            system(argv[4]);
                        break;
                }
 
                prev_state = play_state;
            }
        }
    }
 
    if(client != NULL) {
        mpd_connection_free(client);
    }
    return EXIT_SUCCESS;
}

(also as gist here: https://gist.github.com/sahib/6718139)


Edit: Added error handling // do not consume 100% cpu when connection fails.

Last edited by SahibBommelig (2013-09-26 18:07:56)

Offline

#3 2013-09-25 16:56:17

guikubivan
Member
Registered: 2013-09-25
Posts: 2

Re: Run a script when mpd wants to play a song

Awesome client program, running it as a daemon to manipulate my A/V receiver when a song is played and also add more songs to the play list when stopping (http://mpd.wikia.com/wiki/Hack:random-album.pl).

I did have a problem in that I have a init.d script that runs mpdsonglisten on system start; however, it seems to be taking 100% CPU, any idea why that may be? My laptop has horrible cooling and fragile GPU, so I end up stopping the service and restarting again. MInimal CPU is used after that and anytime outside of system start.

This is the call I'm using to start mpdsonglisten as a daemon:

 start-stop-daemon -c root:root -b --start --quiet --exec /usr/local/bin/mpdsonglisten localhost 6600 /usr/local/bin/mpc_play /usr/local/bin/mpc_stop 

Thanks for any help!

Last edited by guikubivan (2013-09-25 16:56:42)

Offline

#4 2013-09-25 17:00:32

alphaniner
Member
From: Ancapistan
Registered: 2010-07-12
Posts: 2,810

Re: Run a script when mpd wants to play a song

takanuva wrote:

I have built a power strip I can control through USB.

Do you have a link to schematics/plans/etc?


But whether the Constitution really be one thing, or another, this much is certain - that it has either authorized such a government as we have had, or has been powerless to prevent it. In either case, it is unfit to exist.
-Lysander Spooner

Offline

#5 2013-09-26 18:09:58

SahibBommelig
Member
From: Germany
Registered: 2010-05-28
Posts: 80

Re: Run a script when mpd wants to play a song

guikubivan wrote:

Awesome client program, running it as a daemon to manipulate my A/V receiver when a song is played and also add more songs to the play list when stopping (http://mpd.wikia.com/wiki/Hack:random-album.pl).

I did have a problem in that I have a init.d script that runs mpdsonglisten on system start; however, it seems to be taking 100% CPU, any idea why that may be? My laptop has horrible cooling and fragile GPU, so I end up stopping the service and restarting again. MInimal CPU is used after that and anytime outside of system start.

This is the call I'm using to start mpdsonglisten as a daemon:

 start-stop-daemon -c root:root -b --start --quiet --exec /usr/local/bin/mpdsonglisten localhost 6600 /usr/local/bin/mpc_play /usr/local/bin/mpc_stop 

Thanks for any help!

That's the fault of the client program. I've edited my post above with a fixed version. If a error happens (like connection refused) it would enter an endless loop. Now it will try to reconnect every second.

Offline

#6 2013-09-27 18:37:40

guikubivan
Member
Registered: 2013-09-25
Posts: 2

Re: Run a script when mpd wants to play a song

SahibBommelig wrote:

That's the fault of the client program. I've edited my post above with a fixed version. If a error happens (like connection refused) it would enter an endless loop. Now it will try to reconnect every second.

Yay, I confirm it's working flawlessly, very much appreciated!

Offline

#7 2013-09-27 21:42:31

SahibBommelig
Member
From: Germany
Registered: 2010-05-28
Posts: 80

Re: Run a script when mpd wants to play a song

You're welcome. Please prepend [SOLVED] to the thread title.

Offline

Board footer

Powered by FluxBB