size_t decoder_read(struct decoder *decoder, struct input_stream *is, void *buffer, size_t length) { size_t nbytes; assert(decoder == NULL || dc.state == DECODE_STATE_START || dc.state == DECODE_STATE_DECODE); assert(is != NULL); assert(buffer != NULL); if (length == 0) return 0; while (true) { /* XXX don't allow decoder==NULL */ if (decoder != NULL && /* ignore the SEEK command during initialization, the plugin should handle that after it has initialized successfully */ (dc.command != DECODE_COMMAND_SEEK || (dc.state != DECODE_STATE_START && !decoder->seeking)) && dc.command != DECODE_COMMAND_NONE) return 0; nbytes = input_stream_read(is, buffer, length); if (nbytes > 0 || input_stream_eof(is)) return nbytes; /* sleep for a fraction of a second! */ /* XXX don't sleep, wait for an event instead */ g_usleep(10000); } }
static void pcm_stream_decode(struct decoder *decoder, struct input_stream *is) { static const struct audio_format audio_format = { .sample_rate = 44100, .format = SAMPLE_FORMAT_S16, .channels = 2, }; GError *error = NULL; enum decoder_command cmd; double time_to_size = audio_format_time_to_size(&audio_format); float total_time = -1; if (is->size >= 0) total_time = is->size / time_to_size; decoder_initialized(decoder, &audio_format, is->seekable, total_time); do { char buffer[4096]; size_t nbytes = decoder_read(decoder, is, buffer, sizeof(buffer)); if (nbytes == 0 && input_stream_eof(is)) break; cmd = nbytes > 0 ? decoder_data(decoder, is, buffer, nbytes, 0) : decoder_get_command(decoder); if (cmd == DECODE_COMMAND_SEEK) { goffset offset = (goffset)(time_to_size * decoder_seek_where(decoder)); if (input_stream_seek(is, offset, SEEK_SET, &error)) { decoder_command_finished(decoder); } else { g_warning("seeking failed: %s", error->message); g_error_free(error); decoder_seek_error(decoder); } cmd = DECODE_COMMAND_NONE; } } while (cmd == DECODE_COMMAND_NONE); } static const char *const pcm_mime_types[] = { /* for streams obtained by the cdio_paranoia input plugin */ "audio/x-mpd-cdda-pcm", NULL }; const struct decoder_plugin pcm_decoder_plugin = { .name = "pcm", .stream_decode = pcm_stream_decode, .mime_types = pcm_mime_types, };
static int dump_input_stream(struct input_stream *is) { GError *error = NULL; char buffer[4096]; size_t num_read; ssize_t num_written; /* wait until the stream becomes ready */ while (!is->ready) { int ret = input_stream_buffer(is, &error); if (ret < 0) { /* error */ g_warning("%s", error->message); g_error_free(error); return 2; } if (ret == 0) /* nothing was buffered - wait */ g_usleep(10000); } /* print meta data */ if (is->mime != NULL) g_printerr("MIME type: %s\n", is->mime); /* read data and tags from the stream */ while (!input_stream_eof(is)) { struct tag *tag = input_stream_tag(is); if (tag != NULL) { g_printerr("Received a tag:\n"); tag_save(stderr, tag); tag_free(tag); } num_read = input_stream_read(is, buffer, sizeof(buffer), &error); if (num_read == 0) { if (error != NULL) { g_warning("%s", error->message); g_error_free(error); } break; } num_written = write(1, buffer, num_read); if (num_written <= 0) break; } return 0; }
/** * Simple data fetcher. * @param url path or url of data to fetch. * @return data fetched, or NULL on error. Must be freed with g_free. */ static char * lastfm_get(const char *url, GMutex *mutex, GCond *cond) { struct input_stream *input_stream; GError *error = NULL; char buffer[4096]; size_t length = 0, nbytes; input_stream = input_stream_open(url, mutex, cond, &error); if (input_stream == NULL) { if (error != NULL) { g_warning("%s", error->message); g_error_free(error); } return NULL; } g_mutex_lock(mutex); input_stream_wait_ready(input_stream); do { nbytes = input_stream_read(input_stream, buffer + length, sizeof(buffer) - length, &error); if (nbytes == 0) { if (error != NULL) { g_warning("%s", error->message); g_error_free(error); } if (input_stream_eof(input_stream)) break; /* I/O error */ g_mutex_unlock(mutex); input_stream_close(input_stream); return NULL; } length += nbytes; } while (length < sizeof(buffer)); g_mutex_unlock(mutex); input_stream_close(input_stream); return g_strndup(buffer, length); }
size_t decoder_read(struct decoder *decoder, struct input_stream *is, void *buffer, size_t length) { const struct decoder_control *dc = decoder != NULL ? decoder->dc : NULL; GError *error = NULL; size_t nbytes; assert(decoder == NULL || dc->state == DECODE_STATE_START || dc->state == DECODE_STATE_DECODE); assert(is != NULL); assert(buffer != NULL); if (length == 0) return 0; while (true) { /* XXX don't allow decoder==NULL */ if (decoder != NULL && /* ignore the SEEK command during initialization, the plugin should handle that after it has initialized successfully */ (dc->command != DECODE_COMMAND_SEEK || (dc->state != DECODE_STATE_START && !decoder->seeking)) && dc->command != DECODE_COMMAND_NONE) return 0; nbytes = input_stream_read(is, buffer, length, &error); if (G_UNLIKELY(nbytes == 0 && error != NULL)) { g_warning("%s", error->message); g_error_free(error); return 0; } if (nbytes > 0 || input_stream_eof(is)) return nbytes; /* sleep for a fraction of a second! */ /* XXX don't sleep, wait for an event instead */ g_usleep(10000); } }
static int dump_input_stream(struct input_stream *is) { GError *error = NULL; char buffer[4096]; size_t num_read; ssize_t num_written; input_stream_lock(is); /* wait until the stream becomes ready */ input_stream_wait_ready(is); if (!input_stream_check(is, &error)) { g_warning("%s", error->message); g_error_free(error); input_stream_unlock(is); return EXIT_FAILURE; } /* print meta data */ if (is->mime != NULL) g_printerr("MIME type: %s\n", is->mime); /* read data and tags from the stream */ while (!input_stream_eof(is)) { struct tag *tag = input_stream_tag(is); if (tag != NULL) { g_printerr("Received a tag:\n"); tag_save(stderr, tag); tag_free(tag); } num_read = input_stream_read(is, buffer, sizeof(buffer), &error); if (num_read == 0) { if (error != NULL) { g_warning("%s", error->message); g_error_free(error); } break; } num_written = write(1, buffer, num_read); if (num_written <= 0) break; } if (!input_stream_check(is, &error)) { g_warning("%s", error->message); g_error_free(error); input_stream_unlock(is); return EXIT_FAILURE; } input_stream_unlock(is); return 0; }
/** * Read JSON data and parse it using the given YAJL parser. * @param url URL of the JSON data. * @param hand YAJL parser handle. * @return -1 on error, 0 on success. */ static int soundcloud_parse_json(const char *url, yajl_handle hand, GMutex* mutex, GCond* cond) { struct input_stream *input_stream; GError *error = NULL; char buffer[4096]; unsigned char *ubuffer = (unsigned char *)buffer; size_t nbytes; input_stream = input_stream_open(url, mutex, cond, &error); if (input_stream == NULL) { if (error != NULL) { g_warning("%s", error->message); g_error_free(error); } return -1; } g_mutex_lock(mutex); input_stream_wait_ready(input_stream); yajl_status stat; int done = 0; while (!done) { nbytes = input_stream_read(input_stream, buffer, sizeof(buffer), &error); if (nbytes == 0) { if (error != NULL) { g_warning("%s", error->message); g_error_free(error); } if (input_stream_eof(input_stream)) { done = true; } else { g_mutex_unlock(mutex); input_stream_close(input_stream); return -1; } } if (done) stat = yajl_parse_complete(hand); else stat = yajl_parse(hand, ubuffer, nbytes); if (stat != yajl_status_ok && stat != yajl_status_insufficient_data) { unsigned char *str = yajl_get_error(hand, 1, ubuffer, nbytes); g_warning("%s", str); yajl_free_error(hand, str); break; } } g_mutex_unlock(mutex); input_stream_close(input_stream); return 0; }