Logo Search packages:      
Sourcecode: yauap version File versions  Download package

commandline.c

/*
 * commandline.c - commandline frontend for yauap
 * Copyright (c) 2006 Sascha Sommer <ssommer@suse.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* read() */
#include <glib.h>   /* g_timeout_add() g_get_current_dir() */



#include "../yauap.h"
#include "kbd.h"


/* commandline frontend for yauap 
   will accept commands from the keyboard see the README for keybindings
   enqeues all files given on the commandline into a playlist and plays it
   one after another
   quits after the last file
*/

/* track struct */
00041 typedef struct track_s {
    char* url;
    struct track_s* next;
    struct track_s* prev;
} track_t;

/* private data for this frontend */
00048 typedef struct commandline_frontend_s {
    int slave;    /* true if using slave mode */
    int noexit;     /* quit after the last track is played */
    track_t* playlist;
    track_t* playlist_head;
    track_t* current;
} commandline_frontend_t;




static int cmd_quit(yauap_frontend_t* frontend, char* args){
    frontend->player->quit(frontend->player);
    return FALSE;
}

static int cmd_pause(yauap_frontend_t* frontend, char* args){
    return frontend->player->pause(frontend->player);
} 

static int cmd_set_volume(yauap_frontend_t* frontend,char * args){
    player_t* player = frontend->player;
    double volume = player->get_volume(player);
    double value = 5.0;

    if(args)
        value = atof(args);
   
    /* default: value is relative */ 
    volume += value;

    /* check if the value should be handled as absolute */
    if((args = strstr(args," "))){
       if(atoi(args))
           volume = value; 
    }
   
    player->set_volume(player,volume); 
    return 1;
}

static int cmd_next_track(yauap_frontend_t* frontend,char* args){
    commandline_frontend_t* priv = frontend->priv;
    player_t* player = frontend->player;
    player->stop(player);
    while(priv->current){ 
        if(!priv->current->next){
            printf("playlist finished\n");
            if(!priv->noexit){
                player->quit(player);
                return 0;
            }
            return 1;
         }
         priv->current = priv->current->next;
         /* check if we found a playable track */
         if(player->can_decode(priv->current->url)){
           player->load(player,priv->current->url);
           player->start(player);
             break;
         }else{
             printf("can't handle %s\n",priv->current->url);
         }
    }
    return 1;
}
     

static int cmd_prev_track(yauap_frontend_t* frontend,char* args){
    commandline_frontend_t* priv = frontend->priv;
    player_t* player = frontend->player;
    track_t* tmp = priv->current;
    player->stop(player);
    /* try to find a previous track */
    while(tmp){
        tmp = tmp->prev;
        if(tmp && player->can_decode(tmp->url)){
            priv->current = tmp;
            break;
        }
    }
 
    if(priv->current){ 
        player->load(player,priv->current->url);
        player->start(player);
    }
    return 1;
}

static int cmd_get_time_length(yauap_frontend_t* frontend,char* args){
    printf("ANS_LENGTH=%.2lf\n",(double)frontend->player->get_time_length(frontend->player)/1000.0);
    return 1;
}

static int cmd_get_time_pos(yauap_frontend_t* frontend,char* args){
    printf("ANS_TIME_POSITION=%.1f\n",(double)frontend->player->get_time_position(frontend->player)/1000.0 );
    return 1;
}

static int cmd_seek(yauap_frontend_t* frontend,char* args){
    unsigned int pos;
    int value,seek_type=0;
    player_t* player = frontend->player;
    if(!args || !strlen(args)){      //check if args are sane
       printf("invalid seek arguments\n");
       return 1;
    }
    value = atoi(args);             // get value
    args = strstr(args," ");        // get seek_type 

    if(args && strlen(args)){
       seek_type = atoi(args);
    }
   
    pos = player->get_time_position(player);
    if(seek_type == 0){
        pos += value*1000 ;
    }
    player->seek(player,pos);
    return 1;
}


/* output meta information */
static int cmd_info(yauap_frontend_t* frontend,char* args){
    player_t* player = frontend->player;
    char** data=NULL;
    char** ptr;
    player->get_metadata(player,&data);
    for(ptr = data;*ptr;ptr++){
       printf("%s\n",*ptr);
       free(*ptr);
    }
    free(data);
    return 1;
}

/* MPlayer style keyboard and slave mode commands */
static const struct {
    char* command;
    int key;
    int (*func)(yauap_frontend_t* frontend,char* args);
    char* args;
} commandlist[] = {
    {"quit",'q',cmd_quit,NULL},
    {NULL,KEY_ESC,cmd_quit,NULL},
    {"pause",' ',cmd_pause,NULL},
    {NULL,'p',cmd_pause,NULL},
    {NULL,KEY_LEFT,cmd_seek,"-10 0"},
    {NULL,KEY_RIGHT,cmd_seek,"10 0"},
    {NULL,KEY_UP,cmd_seek,"60 0"},
    {NULL,KEY_DOWN,cmd_seek,"-60 0"},
    {NULL,'*',cmd_set_volume,"5.0"},
    {NULL,'/',cmd_set_volume,"-5.0"},
    {NULL,'>',cmd_next_track,NULL},
    {NULL,'<',cmd_prev_track,NULL},
    {"volume",0,cmd_set_volume,NULL},
    {"get_time_length",0,cmd_get_time_length,NULL},
    {"get_time_pos",0,cmd_get_time_pos,NULL},
    {"info",'i',cmd_info,NULL},
};

#define CMD_BUF_LEN 256
/* handle slave commands from stdin */
static int handle_slave_cmd(yauap_frontend_t* frontend){
    char buf[CMD_BUF_LEN];
    int retval;
    int i;
    buf[CMD_BUF_LEN-1]='\0';
    retval=read(0,buf,CMD_BUF_LEN-1);
    if(retval<1) return 1;
    for(i=0;i<sizeof(commandlist) / sizeof(commandlist[0]);i++){
        if(commandlist[i].command && !strncmp(buf,commandlist[i].command,strlen(commandlist[i].command))){
            return commandlist[i].func(frontend,strstr(buf," "));
        }
    }
    return 1;
}

/* handle normal keyboard commands */
static int handle_kbd_cmd(yauap_frontend_t* frontend){
    int key = getch2();
    int i;
    if(key != -1){
        for(i=0;i<sizeof(commandlist) / sizeof(commandlist[0]);i++){
            if(commandlist[i].key == key && commandlist[i].func)
                return commandlist[i].func(frontend,commandlist[i].args);
        }
        printf("\nunhandled key %i\n",key);
    }
    return 1;
}


#define TIME_FORMAT "u:%02u:%02u.%03u"
#define TIME_ARGS(t) \
        t / (1000 * 60 *60), \
        (t / (1000 * 60)) % 60, \
        (t / 1000) % 60, \
        t % 1000




/* check_cmd_callback: checks for commands and displays status information */
static int check_cmd_callback(yauap_frontend_t* frontend){
    player_t* player = frontend->player;
    commandline_frontend_t* priv = frontend->priv;
    int returnv = 1;
    /* display time when not in slave mode */
    if(!priv->slave){
        unsigned int pos = player->get_time_position(player);
        unsigned int len = player->get_time_length(player);
        printf("\r\x1b[KTime: %" TIME_FORMAT " / %" TIME_FORMAT "\n\x1b[A\x1b[K",TIME_ARGS(pos) , TIME_ARGS(len));
    }
    /* handle commands */
    if(priv->slave)
        returnv = handle_slave_cmd(frontend);
    else
        returnv = handle_kbd_cmd(frontend);
    /* call me again */
    return returnv;
}


/* signal callback will be called by the yauap backend */
static void signal_cb(yauap_frontend_t* frontend,unsigned int signal,char* message){
    switch(signal){
        case SIGNAL_EOS:
            cmd_next_track(frontend,NULL);
            break;
        case SIGNAL_METADATA:
            cmd_info(frontend,NULL);
            break;
    }
}



/* function checks if filename is already an uri and converts to
   a file uri otherwise
   the returned string has to be freed
*/

static char* create_url(const char* filename){
    /* playbin always requires absolute paths */
    char* current_dir = g_get_current_dir();
    char* url;
    unsigned int max_len = strlen(current_dir);

    if(!filename)
        return NULL;

    max_len += strlen(filename) + strlen("file://") + 3;

    url = calloc(1,max_len+1);
    if(strstr(filename,"://"))
        strncpy(url,filename,max_len);
    else {  /* assume that filename is a local file */
        if(g_path_is_absolute(filename))
            snprintf(url,max_len,"file://%s",filename);
        else
            snprintf(url,max_len,"file://%s/%s",current_dir,filename);
    }
    free(current_dir);
    return url;
}


/* free frontend resources */
static void commandline_free(yauap_frontend_t* frontend){
    commandline_frontend_t*  priv;
    if(!frontend)
        return;

    priv = frontend->priv;
    /* free playlist */
    while(priv && priv->playlist_head){
       track_t* tmp = priv->playlist_head->prev;
       if(priv->playlist_head->url)
           free(priv->playlist_head->url);
       free(priv->playlist_head);
       priv->playlist_head = tmp;
       if(priv->playlist_head)
          priv->playlist_head->next = NULL;
    }

    if(priv){
        /* disable keyboard */
        if(!priv->slave)
            kbd_disable();
        free(priv);
    }
    free(frontend);
}

static void display_usage(void){
    printf("Commandline usage: yauap [options] url1 [url2]\n"
           "options:\n"
           " -slave start in slave mode\n"
           " -noexit do not exit when the playlist is finished\n"
         "\n"
           "Keybindings:\n"
           " SPACE\n"
           "   Pause/Unpause\n"
           " <- ->\n"
           "   Seek backward/forward 10 seconds.\n"
           " up and down\n"
           "   Seek backward/forward 1 minute.\n"
           " q / ESC\n"
           "   Quit\n"
           " / and *\n"
           "   Decrease/increase volume.\n\n");

}   

yauap_frontend_t* init_commandline(int argc, char* argv[],player_t* player){
    int i;
    yauap_frontend_t* frontend = calloc(1,sizeof(yauap_frontend_t));
    commandline_frontend_t* priv = calloc(1,sizeof(commandline_frontend_t));

    /* fill functions and privdata */
    frontend->priv = priv;
    frontend->free = commandline_free;
    frontend->player = player;
    frontend->signal_cb = signal_cb;

    /* set defaults */
    priv->slave = 0; 

    /* parse arguments */
    for(i=1;i<argc;i++){
        if(!strcmp(argv[i],"-slave"))
            priv->slave = 1;
        if(!strcmp(argv[i],"-noexit"))
            priv->noexit = 1;
        else if(!strcmp(argv[i],"-h")){
            display_usage();
            commandline_free(frontend);
            return NULL;
        }else if(argv[i][0]=='-'){
            //printf("ignoring unknown option %s\n",argv[i]);
        }else { /* append file to playlist */
            if(!priv->playlist)
                priv->playlist = priv->current = priv->playlist_head = calloc(1,sizeof(track_t));
            else{
                priv->playlist_head->next = calloc(1,sizeof(track_t));
                priv->playlist_head->next->prev = priv->playlist_head;
                priv->playlist_head=priv->playlist_head->next;
            }
            priv->playlist_head->url = create_url(argv[i]);
        }
    }

    if(!priv->slave)   /* not runing in slave mode => enable keyboard */
        kbd_enable();


    /* add a player callback that handles input and displays status info */
    g_timeout_add(200, (GSourceFunc) check_cmd_callback, frontend);

    /* if a filename is given try to start playback */
    if(priv->current){
        if(player->can_decode(priv->current->url)){
            player->load(player,priv->current->url);
            player->start(player);
        }else{
            printf("can't handle %s\n",priv->current->url);
            /* go to the first playable url */
            if(!cmd_next_track(frontend,NULL)){
                commandline_free(frontend);
                return NULL;
            }
        }
    }else{
        if(!priv->noexit){
            display_usage();
            commandline_free(frontend);
            return NULL;
        }   
    }

    if(player->verbose)
        printf("commandline frontend inited\n");
    return frontend;
}


Generated by  Doxygen 1.6.0   Back to index