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

main.c

/*
 * yauap - A simple commandline frontend for GStreamer 
 * Copyright (c) 2006 - 2008 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 <string.h>
#include <unistd.h>
#include <gst/gst.h>
#include <gst/pbutils/missing-plugins.h>

#include "yauap.h"

#define VERSION "0.2.4"

#define NUM_FRONTENDS 2
yauap_frontend_t* init_commandline(int argc, char* argv[],player_t* player);
yauap_frontend_t* init_dbus_service(player_t* player);

/* private data */
typedef struct yauap_priv_s {
    char* cdrom_device;
    GMainLoop *loop;
    GstElement *play;   /* the playback pipeline */
    GstTagList* tag_list;
    GstElement *volume;
    float      cur_volume;
    GstElement *audio;  /* audio chain (format conversion, resampling, volume, output sink) */
    int num_frontends;
    yauap_frontend_t** frontends;

    int use_scope;
#define SAMPLE_BUFFER_SIZE (SCOPE_SIZE * 1000)
    unsigned char sample_buffer[SAMPLE_BUFFER_SIZE];
    unsigned int sample_scale;
    int write_pos;
    int read_pos;
    guint64 sample_timestamp;
} yauap_priv_t;

/* send signals to the frontends */
static void signal_frontend(player_t* player,unsigned int signal,char* message){
    yauap_priv_t* priv = player->yauap_priv;    
    int i;
    for(i=0;i<priv->num_frontends;i++){
        yauap_frontend_t* frontend = priv->frontends[i];
        if(frontend && frontend->signal_cb)
           frontend->signal_cb(frontend,signal,message);
    }
}


/* functions that interact with gstreamer they are used by the dbus service*/

/* quit the player */
static int player_quit(player_t* player){
    yauap_priv_t* priv = player->yauap_priv;
    g_main_loop_quit(priv->loop);
    return TRUE;
}

/* pause / unpause */
static int player_pause(player_t* player){
    yauap_priv_t* priv = player->yauap_priv;
    GstState state;
    if(!priv->play)
        return TRUE;


    if(!gst_element_get_state(priv->play, &state, NULL, 0)){
        printf("error: player_pause: gst_element_get_state failed\n");
        return FALSE;
    }
    if(state == GST_STATE_PLAYING){
        gst_element_set_state(priv->play,GST_STATE_PAUSED);
        printf("pause\n");
    }else
        gst_element_set_state(priv->play,GST_STATE_PLAYING);
    return TRUE;
}

/* return time length in ms */
static unsigned int player_get_time_length(player_t* player){
    yauap_priv_t* priv = player->yauap_priv;
    GstFormat fmt = GST_FORMAT_TIME;
    gint64 len = 0;
    if(priv->play)
        gst_element_query_duration(priv->play, &fmt, &len);
    return len / GST_MSECOND;
}

/* return current position in ms */
static unsigned int player_get_time_position(player_t* player){
    yauap_priv_t* priv = player->yauap_priv;
    GstFormat fmt = GST_FORMAT_TIME;
    gint64 pos = 0;
    if(priv->play)
        gst_element_query_position(priv->play, &fmt, &pos);
    return pos / GST_MSECOND;
}

/* stop playback */
static int player_stop(player_t* player){
    yauap_priv_t* priv = player->yauap_priv;
    /* stop playback */
    if(priv->play)
        gst_element_set_state(priv->play, GST_STATE_NULL);
    if(priv->tag_list){
        gst_tag_list_free(priv->tag_list);
        priv->tag_list = NULL;
    }
    return TRUE;
}



/* seek to offset in ms */
static int player_seek(player_t* player,unsigned int offset){
    yauap_priv_t* priv = player->yauap_priv;
    if(player->verbose)
        printf("seeking to %i\n",offset);

    if(!priv->play) 
        return TRUE;

    /* reset sample buffer (for scope) */
    priv->write_pos = priv->read_pos = 0;
    memset(priv->sample_buffer,0,SAMPLE_BUFFER_SIZE);

    if(!gst_element_seek(priv->play,1.0,GST_FORMAT_TIME,GST_SEEK_FLAG_ACCURATE|GST_SEEK_FLAG_FLUSH,
                         GST_SEEK_TYPE_SET,offset * GST_MSECOND,GST_SEEK_TYPE_NONE, 0)){
        printf("seek failed\n");
        player->start(player);

    }
    return TRUE;
}

/* return current volume [0-100] */
static float player_get_volume(player_t* player){
    yauap_priv_t* priv = player->yauap_priv;
    gdouble volume = 0.0;
    /* get current volume */
    if(priv->volume)
        g_object_get( G_OBJECT(priv->volume), "volume", &volume, NULL );
    return volume * 10.0; 
}

/* set new volume [0-100] */
static int player_set_volume(player_t* player,float value){
    yauap_priv_t* priv = player->yauap_priv;
    gdouble volume = value; 

    priv->cur_volume = value;

    if(!priv->volume)
       return TRUE;

    /* change range from 0 - 100 to 0 - 4 */
    volume *= 0.1;
 
    
    /* ajust values */
    if(volume < 0.0)
        volume = 0.0;
    else if(volume > 10.0)
        volume = 10.0;

    printf("\nsetting volume %f\n",value);
    g_object_set(G_OBJECT(priv->volume), "volume", volume, NULL);
    return TRUE;
}


/* start playback */
#define PLAY_TIMEOUT 1000
static int player_start(player_t* player){
    yauap_priv_t* priv = player->yauap_priv;
    GstState state;
    int timeout = PLAY_TIMEOUT;


    if(!priv->play)
        return TRUE;


    /* reset sample buffer (for scope) */
    priv->write_pos = priv->read_pos = 0;
    memset(priv->sample_buffer,0,SAMPLE_BUFFER_SIZE);

    /* start playback */
    gst_element_set_state(priv->play, GST_STATE_PLAYING);

    /* wait until we are really playing back */
    while(timeout > 0 && gst_element_get_state(priv->play, &state, NULL, 0) && state != GST_STATE_PLAYING){
    //    printf("waiting...\n");
        usleep(100);
        --timeout;
    }
    if(timeout <= 0){
        printf("timed out waiting for playback to start\n");
        return TRUE;
    }

    return TRUE;
}

/* metadata handling */

static void list_append_string(char*** ret,const char* tag,char* str){
    unsigned int len = strlen(tag)+strlen(str)+2;
    char* tmp = calloc(1,len);
    snprintf(tmp,len,"%s=%s",tag,str);
    (*ret)[0] = strdup(tmp);
    *ret = *ret + 1;
    free(tmp);
}
static void list_append_uint(char*** ret,const char* tag,unsigned int value){
    char buf[100];
    snprintf(buf,sizeof(buf),"%u",value);
    list_append_string(ret,tag,buf);
}


/* read out metadata and append it to the string list in user_data */
static void tag_for_each(const GstTagList *list,const gchar *tag,gpointer user_data){
    char***ret = user_data;
    GType type = gst_tag_get_type(tag);

    if(type==G_TYPE_STRING){
        char* str_value;
        if(gst_tag_list_get_string(list,tag,&str_value)){
            list_append_string(ret,tag,str_value);
            g_free(str_value);
        }
    }else if(type == G_TYPE_UINT){
        unsigned int uint_value=0;
        if(gst_tag_list_get_uint(list,tag,&uint_value))
            list_append_uint(ret,tag,uint_value);
    }else if(type == GST_TYPE_DATE){
        GDate* date=NULL;
        if(gst_tag_list_get_date(list,tag,&date))
            list_append_uint(ret,tag,g_date_get_year(date));
    }
}

/* count the entries in a taglist */
static void taglist_count_entries(const GstTagList *list,const gchar *tag,gpointer user_data){
    unsigned int* cnt = user_data;
    *cnt = *cnt + 1;
}


/* get a list with all meta infos */
static int player_get_metadata(player_t* player,char*** ret){
    yauap_priv_t* priv = player->yauap_priv;
    GstCaps *caps;
    GstStructure *str;
    GstPad *audiopad = NULL;
    unsigned int num_tags = 0;   
    char**  ptr; 
    gst_tag_list_foreach(priv->tag_list,taglist_count_entries,&num_tags); /* count tags */
    *ret = ptr = calloc(num_tags+4,sizeof(char*)); /* allocate taglist for tags + num_channels + samplerate + length */
    /* get tags from tag_list */
    gst_tag_list_foreach(priv->tag_list,tag_for_each,&ptr);


    /* get samplerate and channels */
    if(priv->audio)
        audiopad = gst_element_get_pad(priv->audio, "sink");
    /* get negotiated caps */
    if(audiopad && GST_IS_PAD(audiopad)){
        int rate=0,channels=0;
        caps = gst_pad_get_negotiated_caps(GST_PAD_CAST(audiopad));

        str = gst_caps_get_structure(caps, 0);

        if(str && gst_structure_get_int(str,"rate",&rate))
            list_append_uint(&ptr,"samplerate",rate);

        if(gst_structure_get_int(str,"channels",&channels))
            list_append_uint(&ptr,"channels",channels);
    }

    /* get length */
    list_append_uint(&ptr,"length",player_get_time_length(player));

    /* terminate the list */
    ptr[0]=NULL;

    /* test */
#if 0
    ptr = *ret;
    while(*ptr){
        printf("%s\n",*ptr);
        ++ptr;
    }
#endif
    return TRUE;
}

/* return current audio sample buffer */
static int player_get_scopedata(player_t* player,char* buf){
    yauap_priv_t* priv = player->yauap_priv;
    unsigned int remaining; 
    if(!priv->use_scope){
        memset(buf,0,SCOPE_SIZE);
        return TRUE;
    }

#if  1
    priv->read_pos = priv->write_pos - SCOPE_SIZE;
    if(priv->read_pos < 0)
        priv->read_pos += SAMPLE_BUFFER_SIZE;
#endif

    remaining = SAMPLE_BUFFER_SIZE - priv->read_pos;

    memcpy(buf,priv->sample_buffer + priv->read_pos,(remaining > SCOPE_SIZE)?SCOPE_SIZE:remaining );
    if(remaining < SCOPE_SIZE)
        memcpy(buf + remaining,priv->sample_buffer,SCOPE_SIZE - remaining); 


    priv->read_pos = (priv->read_pos + SCOPE_SIZE) % SAMPLE_BUFFER_SIZE;

    return TRUE;
}




/* function that handles messages from gstreamer */
static gboolean gstreamer_callback(GstBus *bus,GstMessage *msg,gpointer    data){
    player_t* player = data;
    yauap_priv_t* priv = player->yauap_priv;
    switch (GST_MESSAGE_TYPE (msg)) {
        case GST_MESSAGE_TAG:{
            GstTagList* tlist;
            gst_message_parse_tag(msg,&tlist);
            priv->tag_list = gst_tag_list_merge(priv->tag_list,tlist,GST_TAG_MERGE_PREPEND);

            /* signal metadata change */
            signal_frontend(player,SIGNAL_METADATA,"new metadata"); 
            }
            break;
        case GST_MESSAGE_EOS:
            printf("\nEnd-of-stream\n");
            player_stop(player);
            signal_frontend(player,SIGNAL_EOS,"end of stream");
            break;
      case GST_MESSAGE_ELEMENT:
          if(gst_is_missing_plugin_message(msg)){
              char* desc = gst_missing_plugin_message_get_description(msg);
              char* installer_details = gst_missing_plugin_message_get_installer_detail(msg);
            size_t msg_len = strlen(desc) + strlen(installer_details) + strlen("plugin ") + strlen(" is missing (") + 2;
            char* text = malloc(msg_len);
            snprintf(text,msg_len,"plugin %s is missing (%s)",desc,installer_details);
            if(desc)
                g_free(desc);
            if(installer_details)
                g_free(installer_details);
            printf("\nError: %s\n",text);
            signal_frontend(player,SIGNAL_ERROR,text); 
            free(text);

              signal_frontend(player,SIGNAL_EOS,"unable to continue");

                  player_stop(player);

          }
          break;
        case GST_MESSAGE_ERROR: {
            gchar *debug;
            GError *err;

            gst_message_parse_error (msg, &err, &debug);
            g_free (debug);

            printf("\nError: %s\n", err->message);

            signal_frontend(player,SIGNAL_ERROR,err->message); 

            g_error_free (err);

            signal_frontend(player,SIGNAL_EOS,"unable to continue");

            player_stop(player);

            break;
            }
        default:
            break;
    }
    return TRUE;
}

/* callback function that gets called once the output format of the decoder is figured out
   the audio filter chain gets connected to the pipeline here 
*/
static void cb_new_decoded_pad(GstElement *decodebin,GstPad *pad,gboolean last,gpointer data){
    GstCaps *caps;
    GstStructure *str;
    GstPad *audiopad;
    yauap_priv_t* priv = data;

    /* remove already linked element */
    audiopad = gst_element_get_pad(priv->audio, "sink");
    if (GST_PAD_IS_LINKED(audiopad)) {
        g_object_unref(audiopad);
        return;
    }

    caps = gst_pad_get_caps(pad);
    str = gst_caps_get_structure(caps, 0);

    if (!str || !g_strrstr(gst_structure_get_name(str), "audio")) {
        gst_caps_unref(caps);
        gst_object_unref(audiopad);
        return;
    }
    gst_caps_unref(caps);

    /* link */
    gst_pad_link(pad, audiopad);

}


/* get sample buffer (assumes 16-bit 2 channel audio ) */
static void handoff_cb( GstPad* pad, GstBuffer* buf, gpointer arg){
    player_t* player = arg;
    yauap_priv_t* priv = player->yauap_priv;
    unsigned char* data = GST_BUFFER_DATA(buf);
    unsigned int len = buf->size;
    GstStructure* s = gst_caps_get_structure(GST_BUFFER_CAPS(buf),0);
    int channels = 0;
    int endianness = 0;
    gboolean is_signed = 0;
    int width = 0;
    int space = SAMPLE_BUFFER_SIZE - priv->write_pos;

    s = gst_caps_get_structure ( GST_BUFFER_CAPS( buf ), 0);
    gst_structure_get_int(s,"channels",&channels);
    gst_structure_get_int(s,"endianness",&endianness);
    gst_structure_get_boolean(s,"signed",&is_signed);
    gst_structure_get_int(s,"width",&width);

/*    printf("%s\n", gst_caps_to_string(GST_BUFFER_CAPS(buf))); */

    /* check format */
    if(channels != 2 || endianness != 1234 || ! is_signed || width != 16 )
        return;
 
    if(len > SAMPLE_BUFFER_SIZE){
        printf("increase sample buffer size !!!!!!!!!\n");
        return;
    }

    /* fill scope ring buffer */
    if(space >= len){   
        memcpy(priv->sample_buffer + priv->write_pos,data,len);
    }else{
        memcpy(priv->sample_buffer + priv->write_pos,data,space);
        memcpy(priv->sample_buffer, data + space, len - space); 
    }
    priv->write_pos = ( priv->write_pos + len ) % SAMPLE_BUFFER_SIZE;

    /* update timestamp of the last sample */
    priv->sample_timestamp = GST_BUFFER_TIMESTAMP( buf ) + GST_BUFFER_DURATION( buf ) ;

    /* calculate how many nanoseconds are represented by 1 byte  */
    priv->sample_scale =  GST_BUFFER_DURATION(buf) / GST_BUFFER_SIZE(buf); 

}


/* create/recreate the GStreamer playback pipeline */
static int create_play_pipeline(player_t* player,const char* url){
    yauap_priv_t* priv = player->yauap_priv;
    GstBus *bus;
    GstElement* src = NULL;
    GstElement* decode = NULL;
    GstElement* convert;
    GstElement* resample;
    GstElement* audiosink;
    GstElement* identity;
    GstPad* audiopad;
    GstPad* convertpad;
    gchar* protocol;
    int is_cdda;

    player->stop(player);

    /* destroy the existing pipeline */
    if(priv->play)
        gst_object_unref(GST_OBJECT(priv->play));

    /* check for audio cds */
    protocol = gst_uri_get_protocol(url);
    is_cdda = !strcmp(protocol,"cdda");
    free(protocol);

    /* set up gstreamer pipeline */
    src = gst_element_make_from_uri(GST_URI_SRC, url,"source");
    if(!src){
        printf("element make from uri failed for url %s\n",url);
        return 1;
    }

    /* set cdrom device */
    if(priv->cdrom_device && !strcmp(G_OBJECT_TYPE_NAME(src),"GstCdParanoiaSrc"))
      g_object_set(src, "device", priv->cdrom_device, NULL);

    /* create a simple audio pipeline */
    priv->play = gst_element_factory_make("pipeline","play");

    
    /* create a generic decoder (the src element will be created in player_load) */
    if(!is_cdda)
        decode = gst_element_factory_make("decodebin", "decoder");


    /* create audio filter chain */
    priv->audio = gst_bin_new("audiobin");

    /* create conversion, resample, volume and audio output filters */
    convert = gst_element_factory_make("audioconvert", "convert");
    resample = gst_element_factory_make ("audioresample", "aresample");
    priv->volume = gst_element_factory_make ("volume", "volume");
    audiosink = gst_element_factory_make("gconfaudiosink", "audiosink");
    if (!audiosink)
      audiosink = gst_element_factory_make("autoaudiosink", "audiosink");
    /* clone the data for the scope */
    identity = gst_element_factory_make("identity","identity");

    /* check if the necessary plugins are really installed */
    if(!convert || !resample || !priv->volume || !audiosink || !identity || (!is_cdda && !decode)){
        printf("error couldn't load gstreamer plugins\n");
        printf("convert=%p resample=%p volume=%p audiosink=%p identity=%p decode=%p\n",convert,resample,priv->volume,audiosink,identity,decode);
        return 1;
    }

    /* add them to the pipeline and link them */
    gst_bin_add_many (GST_BIN(priv->audio), convert, identity,priv->volume,resample,audiosink, NULL);

    /* create a sink pad for our audio filter chain similar to the pad of the conversion filter */
    audiopad = gst_element_get_pad(convert, "sink");
    gst_element_add_pad(priv->audio,gst_ghost_pad_new ("sink", audiopad));
    gst_object_unref(audiopad);
    if(priv->use_scope){
        /* add a data probe to the src of the convert pad */
        convertpad = gst_element_get_pad(convert, "src");
        gst_pad_add_buffer_probe(convertpad, G_CALLBACK(handoff_cb), player);
        gst_object_unref(convertpad);
    }


    gst_element_link_many(convert,identity,priv->volume,resample,audiosink,NULL);


    /* add the src element, the audio decoder and the audio filter chain to our pipeline */
    gst_bin_add_many(GST_BIN(priv->play), src, priv->audio, NULL);

    /* no decoder is used for cdda playback */
    if(!is_cdda){
        gst_bin_add(GST_BIN(priv->play),decode);
        gst_element_link(src,decode);
        /* connect the cb_new_decoded_pad callback */
        g_signal_connect(decode, "new-decoded-pad", G_CALLBACK(cb_new_decoded_pad), priv);
    }else
        gst_element_link(src, priv->audio);

    /* connect bus callback */
    bus = gst_pipeline_get_bus(GST_PIPELINE (priv->play));
    gst_bus_add_watch(bus, gstreamer_callback, player);
    gst_object_unref(bus);


    /* set volume */
    if(priv->cur_volume != 200.0)
        player->set_volume(player,priv->cur_volume); 

    return 0;
}

/* load a new url */
static int player_load(player_t* player,const char* url){
    /* uninit */
    player_stop(player);

    printf("loading url %s\n",url);
    if(create_play_pipeline(player,url))
        return TRUE;

    return TRUE;
}


/* get a list of available tracks for the auido cd in cdrom_device */
/* ret will be a NULL terminated list with entires TrackNr=length */
static int player_get_audio_cd_contents(player_t* player,char* cdrom_device, char*** ret){
    yauap_priv_t* priv = player->yauap_priv;
    GstFormat format;

    /* create elements */
    GstElement* src = gst_element_factory_make("cdparanoiasrc", "src");
    GstElement* play = gst_element_factory_make("pipeline","play");
    GstElement* output = gst_element_factory_make("fakesink","output");


    if(!src || !play || !output){
        printf("failed to create the required audio cd elements src=%p play=%p output=%p\n",src,play,output);
        return 0; 
    }

    /* update cdrom_device what a hack */
    if(cdrom_device){
        printf("setting cdrom_device to %s\n",cdrom_device);
        if(priv->cdrom_device)
            free(priv->cdrom_device);
        priv->cdrom_device = strdup(cdrom_device);
    }

    /* create pipeline */
    gst_bin_add_many(GST_BIN(play),src,output,NULL);
    gst_element_link_many(src,output,NULL);

    /* set audio device */
    if(priv->cdrom_device)
        g_object_set(src, "device", priv->cdrom_device, NULL);

    gst_element_set_state( play, GST_STATE_PAUSED ) ;
    if((format = gst_format_get_by_nick("track")) != GST_FORMAT_UNDEFINED){
        int i;
        gint64 tracks = 0;
        char tmp[200];
        if(gst_element_query_duration(play,&format,&tracks)){
            if(tracks)
                *ret = calloc(tracks + 1,sizeof(char*));

            for(i=1;i <= tracks;i++){
                GstFormat fmt = GST_FORMAT_TIME;
                gint64 len = 0;
                gst_element_set_state(play,GST_STATE_NULL);
                g_object_set(src, "track", i, NULL);
                /* reload to update metadata */
                gst_element_set_state(play,GST_STATE_PAUSED);
                gst_element_query_duration(play, &fmt, &len);
                snprintf(tmp,sizeof(tmp),"%i=%lli",i,len / GST_SECOND);
                (*ret)[i-1] = strdup(tmp);
                printf("Track%i len %llis\n",i,len/ GST_SECOND);
            }
        }
    }

    gst_object_unref( GST_OBJECT( play ) );
    return 1;
}





/************************ decodeable check ***************************************/

/* how many microseconds shall we wait for the detection to succeed */
#define DETECT_TIMEOUT 100000


/* callback function that checks if a audio decoder has been added */
static void can_decode_new_decode_pad_callback(GstElement* element, GstPad* pad, gboolean a, gpointer data){
    int* can_decode=data;
    GstCaps* caps = gst_pad_get_caps( pad );
    if(gst_caps_get_size(caps)>0) {
        GstStructure* str = gst_caps_get_structure( caps,0 );
        if(g_strrstr(gst_structure_get_name( str ), "audio" ))
            *can_decode = 1;
    }
    gst_caps_unref( caps );
}

/* callback function that terminates the detection process */
static void can_decode_no_more_pads_callback(GstElement* element, gpointer data){
    int* last = (int*)data;
    *last = 1;
}

/* checks if we are able to decode the audio part of the given url */
/* simply starts playback with fake video and audio output devices */
/* returns nonzero on success, zero otherwise */
/* audio cds always succeed */
static int player_can_decode(const char* url){
    GstElement* src;
    gchar* protocol;
    int can_decode=0;
    int last = 0;
    unsigned int timeout = 0;
    /* create a simple decode pipeline */
    GstElement* play = gst_element_factory_make("pipeline", "can_decode_play");

    if(!play)
        return 0;


    src = gst_element_make_from_uri(GST_URI_SRC, url,"can_decode_source");


    /* check if we can handle the protocol */
    if( !src || !(protocol = gst_uri_get_protocol(url))){
        if(play)
            gst_object_unref( GST_OBJECT( play ) );
        return 0;
    }

    gst_bin_add( GST_BIN( play ), src);

    /* check if we have a decoder for the given format if the uri is no audio cd */
    if(!strcmp(protocol,"cdda"))
        can_decode = 1;
    else {
        GstElement* decodebin =  gst_element_factory_make("decodebin", "can_decode_decode");

        gst_bin_add( GST_BIN( play ), decodebin );
        gst_element_link( src, decodebin );

        /* connect signal handlers */
        g_signal_connect( G_OBJECT( decodebin ), "new-decoded-pad", G_CALLBACK( can_decode_new_decode_pad_callback ), &can_decode );
        g_signal_connect( G_OBJECT( decodebin ), "no-more-pads", G_CALLBACK( can_decode_no_more_pads_callback ), &last );

        /* start decoding */ 
        gst_element_set_state(play,GST_STATE_PLAYING );

        /* wait a bit */
        while ( !can_decode && !last && timeout < DETECT_TIMEOUT ) {
            timeout += 1000;
            usleep(1000);
        }

        /* stop playback */
        gst_element_set_state(play,GST_STATE_NULL);

    }
    g_free(protocol);

    /* destroy pipeline */
    gst_object_unref( GST_OBJECT( play ) );

    return can_decode;
}

/****************************** end decodeabel ***************************************/



static void display_usage(void){
    printf("General usage: yauap [options]\n"
           "General options:\n"
           " -h display this help\n"
           " -cdrom-device set the cdrom device\n"
         "\n");

}   

int main(int argc, char* argv[]){
    player_t* player = calloc(1,sizeof(player_t));
    yauap_priv_t* priv = calloc(1,sizeof(yauap_priv_t));
    int i;
    int run=1;
    
    printf("yauap " VERSION " (C) 2006-2008 Sascha Sommer <ssommer@suse.de>\n");


    /* set function pointers */
    player->quit = player_quit;
    player->pause = player_pause;
    player->can_decode = player_can_decode;
    player->stop = player_stop;
    player->load = player_load;
    player->start = player_start;
    player->get_time_length = player_get_time_length;
    player->get_time_position = player_get_time_position;
    player->seek = player_seek;
    player->get_metadata = player_get_metadata;
    player->get_audio_cd_contents = player_get_audio_cd_contents;
    player->get_scopedata = player_get_scopedata;
    player->get_volume = player_get_volume;
    player->set_volume = player_set_volume;
    player->yauap_priv = priv;
    priv->use_scope = 1;
    priv->cur_volume = 200.0; /* init value == do nothing */
    priv->num_frontends = NUM_FRONTENDS;
    priv->frontends = calloc(1,sizeof(yauap_frontend_t*)*priv->num_frontends);

    /* init gstreamer */
    gst_init(&argc, &argv);



    /* parse generic arguments */
    for(i=1;i<argc;i++){
        if(!strcmp(argv[i],"-h")){
            display_usage();
            run=0;
        }
        else if(!strcmp(argv[i],"-v")){
            player->verbose=1;
        }else if(!strcmp(argv[i],"-cdrom-device")){
            if(i + 1 >= argc){
                printf("-cdrom-device requires a parameter\n");
                run = 0;
            }else{
                ++i;
                priv->cdrom_device=strdup(argv[i]);
                printf("setting cdrom-device %s\n",priv->cdrom_device);
            }
        }
        
    }


    /* create main loop */
    priv->loop = g_main_loop_new(NULL, FALSE);
    priv->tag_list = gst_tag_list_new();

    /* init frontends */
    priv->frontends[0] = init_dbus_service(player);
    priv->frontends[1] = init_commandline(argc, argv,player);

    /* fixme currently we require the commandline frontend */
    if(!priv->frontends[1])
        run = 0;

    /* run the main loop */
    if(run)
        g_main_loop_run(priv->loop);

    /* make sure that we really stopped */
    player_stop(player);


    /* uninit frontends */
    for(i=0;i<priv->num_frontends;i++){
       if(priv->frontends[i] && priv->frontends[i]->free)
           priv->frontends[i]->free(priv->frontends[i]);
    }

    /* clean up */
    if(priv->play)
        gst_object_unref(GST_OBJECT(priv->play));

    
    free(priv->frontends);
    free(priv->cdrom_device);
    free(priv);
    free(player);


    gst_deinit();    
    printf("\n");
    return 0;
}

Generated by  Doxygen 1.6.0   Back to index