Beispiel #1
0
static void roar_plugin_load(input_module_t *mod, const char *nameargs)
{
    im_roar_state *s;
    struct roar_dl_librarypara *para;
    char *name, *args;

    s = mod->internal;

    name = strdup(nameargs);
    args = strstr(name, " ");
    if (args)
    {
        *args = 0;
        args++;
    }

    para = roar_dl_para_new(args, mod, IM_ROAR_APPNAME, IM_ROAR_ABIVERSION);
    if (!para)
    {
        LOG_WARN2("Can not create parameters for plugin %s: %s", name, roar_error2str(roar_error));
        free(name);
        return;
    }

    if (roar_plugincontainer_load(s->plugins, name, para) == -1)
    {
        LOG_WARN2("Can not load plugin %s: %s", name, roar_error2str(roar_error));
    }

    roar_dl_para_unref(para);
    free(name);
}
Beispiel #2
0
void *metadata_thread_signal(void *arg)
{
    char buf[1024];
    input_module_t *mod = arg;

    while(1)
    {
        char **md = NULL;
        int comments = 0;
        FILE *file;

        while(metadata_update_signalled == 0)
        {
            thread_cond_wait(&ices_config->event_pending_cond);
            if (ices_config->shutdown)
            {
                LOG_INFO0 ("metadata thread shutting down");
                return NULL;
            }
            LOG_DEBUG0("meta thread wakeup");
        }

        metadata_update_signalled = 0;

        file = fopen(ices_config->metadata_filename, "r");
        if(!file) {
            LOG_WARN2("Failed to open file \"%s\" for metadata update: %s", 
                    ices_config->metadata_filename, strerror(errno));
            continue;
        }

        LOG_DEBUG1("reading metadata from \"%s\"", ices_config->metadata_filename);
        while(fgets(buf, 1024, file))
        {
            if(buf[0] == '\n')
                break;
            else
            {
                if(buf[strlen(buf)-1] == '\n')
                    buf[strlen(buf)-1] = 0;
                md = realloc(md, (comments+2)*sizeof(char *));
                md[comments] = malloc(strlen(buf)+1);

                memcpy(md[comments], buf, strlen(buf)+1);
                comments++;
                LOG_INFO2 ("tag %d is %s", comments, buf);
            }
        }

        fclose(file);

        if(md) /* Don't update if there's nothing there */
        {
            md[comments]=0;

            /* Now, let's actually use the new data */
            LOG_INFO0("Updating metadata");
            mod->handle_event(mod,EVENT_METADATAUPDATE,md);
        }
        else
            LOG_INFO0("No metadata has been read");

    }
}
Beispiel #3
0
/* Core streaming function for this module
 * This is what actually produces the data which gets streamed.
 *
 * returns:  >0  Number of bytes read
 *            0  Non-fatal error.
 *           <0  Fatal error.
 */
static int playlist_read(void *self, ref_buffer *rb)
{
    playlist_state_t *pl = (playlist_state_t *)self;
    int bytes;
    unsigned char *buf;
    char *newfn;
    int result;
    ogg_page og;

    if (pl->errors > 5) 
    {
        LOG_WARN0("Too many consecutive errors - exiting");
        return -1;
    }

    if (!pl->current_file || pl->nexttrack) 
    {
        pl->nexttrack = 0;

        if (pl->current_file && strcmp (pl->filename, "-"))
        {
            fclose(pl->current_file);
            pl->current_file = NULL;
        }
	if (pl->file_ended)
	{
	    pl->file_ended(pl->data, pl->filename);
	}

        newfn = pl->get_filename(pl->data);
        if (!newfn)
        {
            LOG_INFO0("No more filenames available, end of playlist");
            return -1; /* No more files available */
        }

        if (strcmp (newfn, "-"))
        {
            if (!pl->allow_repeat && pl->filename && !strcmp(pl->filename, newfn))
            {
                LOG_ERROR0("Cannot play same file twice in a row, skipping");
                pl->errors++;
                pl->free_filename (pl->data, newfn);
                return 0;
            }
            pl->free_filename(pl->data, pl->filename);
            pl->filename = newfn;

            pl->current_file = fopen(pl->filename, "rb");
            if (!pl->current_file) 
            {
                LOG_WARN2("Error opening file \"%s\": %s",pl->filename, strerror(errno));
                pl->errors++;
                return 0;
            }
            LOG_INFO1("Currently playing \"%s\"", pl->filename);
        }
        else
        {
            LOG_INFO0("Currently playing from stdin");
            pl->current_file = stdin;
            pl->free_filename(pl->data, pl->filename);
            pl->filename = newfn;
        }

        /* Reinit sync, so that dead data from previous file is discarded */
        ogg_sync_clear(&pl->oy);
        ogg_sync_init(&pl->oy);
    }
    input_sleep ();

    while(1)
    {
        result = ogg_sync_pageout(&pl->oy, &og);
        if(result < 0)
            LOG_WARN1("Corrupt or missing data in file (%s)", pl->filename);
        else if(result > 0)
        {
            if (ogg_page_bos (&og))
            {
               if (ogg_page_serialno (&og) == pl->current_serial)
                   LOG_WARN1 ("detected duplicate serial number reading \"%s\"", pl->filename);

               pl->current_serial = ogg_page_serialno (&og);
            }
            if (input_calculate_ogg_sleep (&og) < 0)
            {
                pl->nexttrack = 1;
                return 0;
            }
            rb->len = og.header_len + og.body_len;
            rb->buf = malloc(rb->len);
            rb->aux_data = og.header_len;

            memcpy(rb->buf, og.header, og.header_len);
            memcpy(rb->buf+og.header_len, og.body, og.body_len);
            if(ogg_page_granulepos(&og)==0)
                rb->critical = 1;
            break;
        }

        /* If we got to here, we didn't have enough data. */
        buf = ogg_sync_buffer(&pl->oy, BUFSIZE);
        bytes = fread(buf,1, BUFSIZE, pl->current_file);
        if (bytes <= 0) 
        {
            if (feof(pl->current_file)) 
            {
                pl->nexttrack = 1;
                return playlist_read(pl,rb);
            } 
            else 
            {
                LOG_ERROR2("Read error from \"%s\": %s", pl->filename, strerror(errno));
                fclose(pl->current_file);
                pl->current_file=NULL;
                pl->errors++;
                return 0; 
            }
        }
        else
            ogg_sync_wrote(&pl->oy, bytes);
    }

    pl->errors=0;

    return rb->len;
}
Beispiel #4
0
input_module_t *roar_open_module(module_param_t *params)
{
    input_module_t *mod = calloc(1, sizeof(input_module_t));
    im_roar_state *s;
    module_param_t *current;
    const char * server = NULL;
    int    dir    = ROAR_DIR_MONITOR;
    enum { MD_NONE = 0, MD_FILE = 1, MD_STREAM = 2 } use_metadata = MD_STREAM;
    int err;

    mod->getdata = roar_read;
    mod->handle_event = event_handler;
    mod->metadata_update = metadata_update;

    mod->internal = calloc(1, sizeof(im_roar_state));
    s = mod->internal;

    if(roar_profile2info(&s->info, "default") == -1)
    {
        LOG_ERROR1("Failed to get default audio profile: %s",
                roar_error2str(roar_error));
        return NULL;
    }
    s->info.bits = 16;

    s->vss       = NULL;

    s->plugins   = roar_plugincontainer_new_simple(IM_ROAR_APPNAME, IM_ROAR_ABIVERSION);
    if (!s->plugins)
    {
        LOG_ERROR1("Failed to create plugin container: %s",
                roar_error2str(roar_error));
        return NULL;
    }

    thread_mutex_create(&s->metadatalock);

    current = params;

    while(current)
    {
        if(!strcmp(current->name, "rate"))
            s->info.rate = roar_str2rate(current->value);
        else if(!strcmp(current->name, "channels"))
            s->info.channels = roar_str2channels(current->value);
        else if(!strcmp(current->name, "codec"))
            s->info.codec = roar_str2codec(current->value);
        else if(!strcmp(current->name, "aiprofile")) {
            if (roar_profile2info(&s->info, current->value) == -1) {
                LOG_WARN2("Can not get audio info profile %s: %s", current->value, roar_error2str(roar_error));
            }
            s->info.bits = 16;
        } else if(!strcmp(current->name, "dir")) {
            if ( !strcasecmp(current->value, "monitor") ) {
                dir = ROAR_DIR_MONITOR;
            } else if ( !strcasecmp(current->value, "record") ) {
                dir = ROAR_DIR_RECORD;
            } else {
                LOG_WARN2("Unknown value %s for parameter %s for roar module", current->value, current->name);
            }
        } else if(!strcmp(current->name, "device") || !strcmp(current->name, "server"))
            server = current->value;
        else if(!strcmp(current->name, "metadata")) {
            if ( !strcasecmp(current->value, "none") ) {
                use_metadata = MD_NONE;
            } else if ( !strcasecmp(current->value, "file") ) {
                use_metadata = MD_FILE;
            } else if ( !strcasecmp(current->value, "stream") ) {
                use_metadata = MD_STREAM;
            } else {
                use_metadata = atoi(current->value);
            }
        } else if(!strcmp(current->name, "metadatafilename")) {
            ices_config->metadata_filename = current->value;
            use_metadata = MD_FILE;
        } else if(!strcmp(current->name, "plugin")) {
            roar_plugin_load(mod, current->value);
        } else
            LOG_WARN1("Unknown parameter %s for roar module", current->name);

        current = current->next;
    }

    mod->type = ICES_INPUT_PCM;

    switch (s->info.codec) {
        case ROAR_CODEC_PCM_LE:
          mod->subtype = INPUT_PCM_LE_16;
         break;
        case ROAR_CODEC_PCM_BE:
          mod->subtype = INPUT_PCM_BE_16;
         break;
        case ROAR_CODEC_OGG_GENERAL:
          LOG_WARN0("Codec may not work, specify ogg_vorbis for Vorbis streaming");
        case ROAR_CODEC_OGG_VORBIS:
          mod->type = ICES_INPUT_VORBIS;
          // we do not set mod->subtype here, strange design ices2 has...
         break;
        case -1:
         LOG_ERROR0("Unknown Codec");
         return NULL;
        default:
         LOG_ERROR1("Unsupported Codec: %s", roar_codec2str(s->info.codec));
         return NULL;
    }

    roar_plugincontainer_appsched_trigger(s->plugins, ROAR_DL_APPSCHED_INIT);

    /* Open the VS connection */
    if ( (s->vss = roar_vs_new(server, IM_ROAR_PROGNAME, &err)) == NULL ) {
        LOG_ERROR2("Failed to open sound server %s: %s",
                server, roar_vs_strerr(err));
        goto fail;
    }

    /* Now, set the required parameters on that device */
    if ( roar_vs_stream(s->vss, &s->info, dir, &err) == -1 ) { 
        LOG_ERROR2("Failed to create a new stream on sound server %s: %s",
                server, roar_vs_strerr(err));
        goto fail;
    }

    if ( _set_flags(roar_vs_connection_obj(s->vss, NULL), roar_vs_stream_obj(s->vss, NULL),
                                ROAR_FLAG_META, ROAR_RESET_FLAG) != 0 ) {
        LOG_WARN0("Can not reset metadata flag from stream");
    }

    /* We're done, and we didn't fail! */
    LOG_INFO3("Opened sound server at %s at %d channel(s), %d Hz", 
            server, s->info.channels, s->info.rate);

    switch (use_metadata) {
     case MD_NONE:
      break;
     case MD_FILE:
        LOG_INFO0("Starting metadata update thread");
        if(ices_config->metadata_filename)
            thread_create("im_roar-metadata", metadata_thread_signal, mod, 1);
        else
            thread_create("im_roar-metadata", metadata_thread_stdin, mod, 1);
      break;
     case MD_STREAM:
        if ( _set_flags(roar_vs_connection_obj(s->vss, NULL), roar_vs_stream_obj(s->vss, NULL),
                                    ROAR_FLAG_META, ROAR_SET_FLAG) != 0 ) {
            LOG_WARN0("Can not set metadata flag from stream");
        }
      break;
    }

    return mod;

fail:
    close_module(mod); /* safe, this checks for valid contents */
    return NULL;
}