Commit c22cbbf8 authored by Max Kellermann's avatar Max Kellermann

Merge branch 'v0.16.x'

Conflicts: src/output/osx_plugin.c src/text_input_stream.c
parents f930f37d 5acee73f
...@@ -1170,6 +1170,27 @@ test_run_encoder_LDADD = \ ...@@ -1170,6 +1170,27 @@ test_run_encoder_LDADD = \
$(GLIB_LIBS) $(GLIB_LIBS)
endif endif
if ENABLE_VORBIS_ENCODER
noinst_PROGRAMS += test/test_vorbis_encoder
test_test_vorbis_encoder_SOURCES = test/test_vorbis_encoder.c \
test/stdbin.h \
src/conf.c src/tokenizer.c \
src/utils.c \
src/string_util.c \
src/tag.c src/tag_pool.c \
src/audio_check.c \
src/audio_format.c \
src/audio_parser.c \
src/pcm_buffer.c \
src/fifo_buffer.c src/growing_fifo.c \
$(ENCODER_SRC)
test_test_vorbis_encoder_CPPFLAGS = $(AM_CPPFLAGS) \
$(ENCODER_CFLAGS)
test_test_vorbis_encoder_LDADD = $(MPD_LIBS) \
$(ENCODER_LIBS) \
$(GLIB_LIBS)
endif
test_software_volume_SOURCES = test/software_volume.c \ test_software_volume_SOURCES = test/software_volume.c \
test/stdbin.h \ test/stdbin.h \
src/audio_check.c \ src/audio_check.c \
......
...@@ -44,6 +44,15 @@ ver 0.16.8 (2012/??/??) ...@@ -44,6 +44,15 @@ ver 0.16.8 (2012/??/??)
* decoder: * decoder:
- vorbis (and others): fix seeking at startup - vorbis (and others): fix seeking at startup
- ffmpeg: read the "year" tag - ffmpeg: read the "year" tag
* encoder:
- vorbis: generate end-of-stream packet before tag
- vorbis: generate end-of-stream packet when playback ends
* output:
- jack: check for connection failure before starting playback
- jack: workaround for libjack1 crash bug
- osx: fix stuttering due to buffering bug
* fix endless loop in text file reader
* update: skip symlinks in path that is to be updated
ver 0.16.7 (2012/02/04) ver 0.16.7 (2012/02/04)
......
...@@ -86,7 +86,15 @@ directory_delete(struct directory *directory) ...@@ -86,7 +86,15 @@ directory_delete(struct directory *directory)
const char * const char *
directory_get_name(const struct directory *directory) directory_get_name(const struct directory *directory)
{ {
return g_basename(directory->path); assert(!directory_is_root(directory));
assert(directory->path != NULL);
const char *slash = strrchr(directory->path, '/');
assert((slash == NULL) == directory_is_root(directory->parent));
return slash != NULL
? slash + 1
: directory->path;
} }
struct directory * struct directory *
......
...@@ -354,6 +354,7 @@ const struct encoder_plugin flac_encoder_plugin = { ...@@ -354,6 +354,7 @@ const struct encoder_plugin flac_encoder_plugin = {
.finish = flac_encoder_finish, .finish = flac_encoder_finish,
.open = flac_encoder_open, .open = flac_encoder_open,
.close = flac_encoder_close, .close = flac_encoder_close,
.end = flac_encoder_flush,
.flush = flac_encoder_flush, .flush = flac_encoder_flush,
.write = flac_encoder_write, .write = flac_encoder_write,
.read = flac_encoder_read, .read = flac_encoder_read,
......
...@@ -300,6 +300,7 @@ const struct encoder_plugin twolame_encoder_plugin = { ...@@ -300,6 +300,7 @@ const struct encoder_plugin twolame_encoder_plugin = {
.finish = twolame_encoder_finish, .finish = twolame_encoder_finish,
.open = twolame_encoder_open, .open = twolame_encoder_open,
.close = twolame_encoder_close, .close = twolame_encoder_close,
.end = twolame_encoder_flush,
.flush = twolame_encoder_flush, .flush = twolame_encoder_flush,
.write = twolame_encoder_write, .write = twolame_encoder_write,
.read = twolame_encoder_read, .read = twolame_encoder_read,
......
...@@ -285,8 +285,6 @@ vorbis_encoder_pre_tag(struct encoder *_encoder, G_GNUC_UNUSED GError **error) ...@@ -285,8 +285,6 @@ vorbis_encoder_pre_tag(struct encoder *_encoder, G_GNUC_UNUSED GError **error)
vorbis_analysis_init(&encoder->vd, &encoder->vi); vorbis_analysis_init(&encoder->vd, &encoder->vi);
vorbis_block_init(&encoder->vd, &encoder->vb); vorbis_block_init(&encoder->vd, &encoder->vb);
ogg_stream_reset(&encoder->os);
encoder->flush = true; encoder->flush = true;
return true; return true;
} }
...@@ -407,6 +405,7 @@ const struct encoder_plugin vorbis_encoder_plugin = { ...@@ -407,6 +405,7 @@ const struct encoder_plugin vorbis_encoder_plugin = {
.finish = vorbis_encoder_finish, .finish = vorbis_encoder_finish,
.open = vorbis_encoder_open, .open = vorbis_encoder_open,
.close = vorbis_encoder_close, .close = vorbis_encoder_close,
.end = vorbis_encoder_pre_tag,
.flush = vorbis_encoder_flush, .flush = vorbis_encoder_flush,
.pre_tag = vorbis_encoder_pre_tag, .pre_tag = vorbis_encoder_pre_tag,
.tag = vorbis_encoder_tag, .tag = vorbis_encoder_tag,
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <glib.h> #include <glib.h>
#include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
...@@ -32,6 +33,10 @@ struct tag; ...@@ -32,6 +33,10 @@ struct tag;
struct encoder { struct encoder {
const struct encoder_plugin *plugin; const struct encoder_plugin *plugin;
#ifndef NDEBUG
bool open, pre_tag, tag, end;
#endif
}; };
struct encoder_plugin { struct encoder_plugin {
...@@ -48,6 +53,8 @@ struct encoder_plugin { ...@@ -48,6 +53,8 @@ struct encoder_plugin {
void (*close)(struct encoder *encoder); void (*close)(struct encoder *encoder);
bool (*end)(struct encoder *encoder, GError **error);
bool (*flush)(struct encoder *encoder, GError **error); bool (*flush)(struct encoder *encoder, GError **error);
bool (*pre_tag)(struct encoder *encoder, GError **error); bool (*pre_tag)(struct encoder *encoder, GError **error);
...@@ -73,6 +80,10 @@ encoder_struct_init(struct encoder *encoder, ...@@ -73,6 +80,10 @@ encoder_struct_init(struct encoder *encoder,
const struct encoder_plugin *plugin) const struct encoder_plugin *plugin)
{ {
encoder->plugin = plugin; encoder->plugin = plugin;
#ifndef NDEBUG
encoder->open = false;
#endif
} }
/** /**
...@@ -98,6 +109,8 @@ encoder_init(const struct encoder_plugin *plugin, ...@@ -98,6 +109,8 @@ encoder_init(const struct encoder_plugin *plugin,
static inline void static inline void
encoder_finish(struct encoder *encoder) encoder_finish(struct encoder *encoder)
{ {
assert(!encoder->open);
encoder->plugin->finish(encoder); encoder->plugin->finish(encoder);
} }
...@@ -116,7 +129,14 @@ static inline bool ...@@ -116,7 +129,14 @@ static inline bool
encoder_open(struct encoder *encoder, struct audio_format *audio_format, encoder_open(struct encoder *encoder, struct audio_format *audio_format,
GError **error) GError **error)
{ {
return encoder->plugin->open(encoder, audio_format, error); assert(!encoder->open);
bool success = encoder->plugin->open(encoder, audio_format, error);
#ifndef NDEBUG
encoder->open = success;
encoder->pre_tag = encoder->tag = encoder->end = false;
#endif
return success;
} }
/** /**
...@@ -128,8 +148,43 @@ encoder_open(struct encoder *encoder, struct audio_format *audio_format, ...@@ -128,8 +148,43 @@ encoder_open(struct encoder *encoder, struct audio_format *audio_format,
static inline void static inline void
encoder_close(struct encoder *encoder) encoder_close(struct encoder *encoder)
{ {
assert(encoder->open);
if (encoder->plugin->close != NULL) if (encoder->plugin->close != NULL)
encoder->plugin->close(encoder); encoder->plugin->close(encoder);
#ifndef NDEBUG
encoder->open = false;
#endif
}
/**
* Ends the stream: flushes the encoder object, generate an
* end-of-stream marker (if applicable), make everything which might
* currently be buffered available by encoder_read().
*
* After this function has been called, the encoder may not be usable
* for more data, and only encoder_read() and encoder_close() can be
* called.
*
* @param encoder the encoder
* @param error location to store the error occuring, or NULL to ignore errors.
* @return true on success
*/
static inline bool
encoder_end(struct encoder *encoder, GError **error)
{
assert(encoder->open);
assert(!encoder->end);
#ifndef NDEBUG
encoder->end = true;
#endif
/* this method is optional */
return encoder->plugin->end != NULL
? encoder->plugin->end(encoder, error)
: true;
} }
/** /**
...@@ -143,6 +198,11 @@ encoder_close(struct encoder *encoder) ...@@ -143,6 +198,11 @@ encoder_close(struct encoder *encoder)
static inline bool static inline bool
encoder_flush(struct encoder *encoder, GError **error) encoder_flush(struct encoder *encoder, GError **error)
{ {
assert(encoder->open);
assert(!encoder->pre_tag);
assert(!encoder->tag);
assert(!encoder->end);
/* this method is optional */ /* this method is optional */
return encoder->plugin->flush != NULL return encoder->plugin->flush != NULL
? encoder->plugin->flush(encoder, error) ? encoder->plugin->flush(encoder, error)
...@@ -162,10 +222,20 @@ encoder_flush(struct encoder *encoder, GError **error) ...@@ -162,10 +222,20 @@ encoder_flush(struct encoder *encoder, GError **error)
static inline bool static inline bool
encoder_pre_tag(struct encoder *encoder, GError **error) encoder_pre_tag(struct encoder *encoder, GError **error)
{ {
assert(encoder->open);
assert(!encoder->pre_tag);
assert(!encoder->tag);
assert(!encoder->end);
/* this method is optional */ /* this method is optional */
return encoder->plugin->pre_tag != NULL bool success = encoder->plugin->pre_tag != NULL
? encoder->plugin->pre_tag(encoder, error) ? encoder->plugin->pre_tag(encoder, error)
: true; : true;
#ifndef NDEBUG
encoder->pre_tag = success;
#endif
return success;
} }
/** /**
...@@ -182,6 +252,15 @@ encoder_pre_tag(struct encoder *encoder, GError **error) ...@@ -182,6 +252,15 @@ encoder_pre_tag(struct encoder *encoder, GError **error)
static inline bool static inline bool
encoder_tag(struct encoder *encoder, const struct tag *tag, GError **error) encoder_tag(struct encoder *encoder, const struct tag *tag, GError **error)
{ {
assert(encoder->open);
assert(!encoder->pre_tag);
assert(encoder->tag);
assert(!encoder->end);
#ifndef NDEBUG
encoder->tag = false;
#endif
/* this method is optional */ /* this method is optional */
return encoder->plugin->tag != NULL return encoder->plugin->tag != NULL
? encoder->plugin->tag(encoder, tag, error) ? encoder->plugin->tag(encoder, tag, error)
...@@ -201,6 +280,11 @@ static inline bool ...@@ -201,6 +280,11 @@ static inline bool
encoder_write(struct encoder *encoder, const void *data, size_t length, encoder_write(struct encoder *encoder, const void *data, size_t length,
GError **error) GError **error)
{ {
assert(encoder->open);
assert(!encoder->pre_tag);
assert(!encoder->tag);
assert(!encoder->end);
return encoder->plugin->write(encoder, data, length, error); return encoder->plugin->write(encoder, data, length, error);
} }
...@@ -215,6 +299,16 @@ encoder_write(struct encoder *encoder, const void *data, size_t length, ...@@ -215,6 +299,16 @@ encoder_write(struct encoder *encoder, const void *data, size_t length,
static inline size_t static inline size_t
encoder_read(struct encoder *encoder, void *dest, size_t length) encoder_read(struct encoder *encoder, void *dest, size_t length)
{ {
assert(encoder->open);
assert(!encoder->pre_tag || !encoder->tag);
#ifndef NDEBUG
if (encoder->pre_tag) {
encoder->pre_tag = false;
encoder->tag = true;
}
#endif
return encoder->plugin->read(encoder, dest, length); return encoder->plugin->read(encoder, dest, length);
} }
......
...@@ -146,6 +146,13 @@ mpd_jack_process(jack_nframes_t nframes, void *arg) ...@@ -146,6 +146,13 @@ mpd_jack_process(jack_nframes_t nframes, void *arg)
for (unsigned i = 0; i < jd->audio_format.channels; ++i) { for (unsigned i = 0; i < jd->audio_format.channels; ++i) {
out = jack_port_get_buffer(jd->ports[i], nframes); out = jack_port_get_buffer(jd->ports[i], nframes);
if (out == NULL)
/* workaround for libjack1 bug: if the server
connection fails, the process callback is
invoked anyway, but unable to get a
buffer */
continue;
jack_ringbuffer_read(jd->ringbuffer[i], jack_ringbuffer_read(jd->ringbuffer[i],
(char *)out, available * jack_sample_size); (char *)out, available * jack_sample_size);
...@@ -159,6 +166,12 @@ mpd_jack_process(jack_nframes_t nframes, void *arg) ...@@ -159,6 +166,12 @@ mpd_jack_process(jack_nframes_t nframes, void *arg)
for (unsigned i = jd->audio_format.channels; for (unsigned i = jd->audio_format.channels;
i < jd->num_source_ports; ++i) { i < jd->num_source_ports; ++i) {
out = jack_port_get_buffer(jd->ports[i], nframes); out = jack_port_get_buffer(jd->ports[i], nframes);
if (out == NULL)
/* workaround for libjack1 bug: if the server
connection fails, the process callback is
invoked anyway, but unable to get a
buffer */
continue;
for (jack_nframes_t f = 0; f < nframes; ++f) for (jack_nframes_t f = 0; f < nframes; ++f)
out[f] = 0.0; out[f] = 0.0;
...@@ -572,6 +585,9 @@ mpd_jack_open(struct audio_output *ao, struct audio_format *audio_format, ...@@ -572,6 +585,9 @@ mpd_jack_open(struct audio_output *ao, struct audio_format *audio_format,
jd->pause = false; jd->pause = false;
if (jd->client != NULL && jd->shutdown)
mpd_jack_disconnect(jd);
if (jd->client == NULL && !mpd_jack_connect(jd, error_r)) if (jd->client == NULL && !mpd_jack_connect(jd, error_r))
return false; return false;
......
/* /*
* Copyright (C) 2003-2011 The Music Player Daemon Project * Copyright (C) 2003-2012 The Music Player Daemon Project
* http://www.musicpd.org * http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "osx_output_plugin.h" #include "osx_output_plugin.h"
#include "output_api.h" #include "output_api.h"
#include "fifo_buffer.h"
#include <glib.h> #include <glib.h>
#include <CoreAudio/AudioHardware.h> #include <CoreAudio/AudioHardware.h>
...@@ -40,10 +41,8 @@ struct osx_output { ...@@ -40,10 +41,8 @@ struct osx_output {
AudioUnit au; AudioUnit au;
GMutex *mutex; GMutex *mutex;
GCond *condition; GCond *condition;
char *buffer;
size_t buffer_size; struct fifo_buffer *buffer;
size_t pos;
size_t len;
}; };
/** /**
...@@ -96,11 +95,6 @@ osx_output_init(const struct config_param *param, GError **error_r) ...@@ -96,11 +95,6 @@ osx_output_init(const struct config_param *param, GError **error_r)
oo->mutex = g_mutex_new(); oo->mutex = g_mutex_new();
oo->condition = g_cond_new(); oo->condition = g_cond_new();
oo->pos = 0;
oo->len = 0;
oo->buffer = NULL;
oo->buffer_size = 0;
return &oo->base; return &oo->base;
} }
...@@ -109,7 +103,6 @@ osx_output_finish(struct audio_output *ao) ...@@ -109,7 +103,6 @@ osx_output_finish(struct audio_output *ao)
{ {
struct osx_output *od = (struct osx_output *)ao; struct osx_output *od = (struct osx_output *)ao;
g_free(od->buffer);
g_mutex_free(od->mutex); g_mutex_free(od->mutex);
g_cond_free(od->condition); g_cond_free(od->condition);
g_free(od); g_free(od);
...@@ -215,37 +208,29 @@ osx_render(void *vdata, ...@@ -215,37 +208,29 @@ osx_render(void *vdata,
struct osx_output *od = (struct osx_output *) vdata; struct osx_output *od = (struct osx_output *) vdata;
AudioBuffer *buffer = &buffer_list->mBuffers[0]; AudioBuffer *buffer = &buffer_list->mBuffers[0];
size_t buffer_size = buffer->mDataByteSize; size_t buffer_size = buffer->mDataByteSize;
size_t bytes_to_copy;
size_t trailer_length;
size_t dest_pos = 0;
g_mutex_lock(od->mutex); assert(od->buffer != NULL);
bytes_to_copy = MIN(od->len, buffer_size); g_mutex_lock(od->mutex);
od->len -= bytes_to_copy;
trailer_length = od->buffer_size - od->pos; size_t nbytes;
if (bytes_to_copy > trailer_length) { const void *src = fifo_buffer_read(od->buffer, &nbytes);
memcpy((unsigned char*)buffer->mData + dest_pos,
od->buffer + od->pos, trailer_length);
od->pos = 0;
dest_pos += trailer_length;
bytes_to_copy -= trailer_length;
}
memcpy((unsigned char*)buffer->mData + dest_pos, if (src != NULL) {
od->buffer + od->pos, bytes_to_copy); if (nbytes > buffer_size)
od->pos += bytes_to_copy; nbytes = buffer_size;
if (od->pos >= od->buffer_size) memcpy(buffer->mData, src, nbytes);
od->pos = 0; fifo_buffer_consume(od->buffer, nbytes);
} else
nbytes = 0;
g_cond_signal(od->condition); g_cond_signal(od->condition);
g_mutex_unlock(od->mutex); g_mutex_unlock(od->mutex);
if (bytes_to_copy < buffer_size) if (nbytes < buffer_size)
memset((unsigned char*)buffer->mData + bytes_to_copy, 0, memset((unsigned char*)buffer->mData + nbytes, 0,
buffer_size - bytes_to_copy); buffer_size - nbytes);
return 0; return 0;
} }
...@@ -315,7 +300,7 @@ osx_output_cancel(struct audio_output *ao) ...@@ -315,7 +300,7 @@ osx_output_cancel(struct audio_output *ao)
struct osx_output *od = (struct osx_output *)ao; struct osx_output *od = (struct osx_output *)ao;
g_mutex_lock(od->mutex); g_mutex_lock(od->mutex);
od->len = 0; fifo_buffer_clear(od->buffer);
g_mutex_unlock(od->mutex); g_mutex_unlock(od->mutex);
} }
...@@ -326,6 +311,8 @@ osx_output_close(struct audio_output *ao) ...@@ -326,6 +311,8 @@ osx_output_close(struct audio_output *ao)
AudioOutputUnitStop(od->au); AudioOutputUnitStop(od->au);
AudioUnitUninitialize(od->au); AudioUnitUninitialize(od->au);
fifo_buffer_free(od->buffer);
} }
static bool static bool
...@@ -387,12 +374,8 @@ osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GErr ...@@ -387,12 +374,8 @@ osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GErr
} }
/* create a buffer of 1s */ /* create a buffer of 1s */
od->buffer_size = (audio_format->sample_rate) * od->buffer = fifo_buffer_new(audio_format->sample_rate *
audio_format_frame_size(audio_format); audio_format_frame_size(audio_format));
od->buffer = g_realloc(od->buffer, od->buffer_size);
od->pos = 0;
od->len = 0;
status = AudioOutputUnitStart(od->au); status = AudioOutputUnitStart(od->au);
if (status != 0) { if (status != 0) {
...@@ -411,33 +394,30 @@ osx_output_play(struct audio_output *ao, const void *chunk, size_t size, ...@@ -411,33 +394,30 @@ osx_output_play(struct audio_output *ao, const void *chunk, size_t size,
G_GNUC_UNUSED GError **error) G_GNUC_UNUSED GError **error)
{ {
struct osx_output *od = (struct osx_output *)ao; struct osx_output *od = (struct osx_output *)ao;
size_t start, nbytes;
g_mutex_lock(od->mutex); g_mutex_lock(od->mutex);
while (od->len >= od->buffer_size) void *dest;
/* wait for some free space in the buffer */ size_t max_length;
g_cond_wait(od->condition, od->mutex);
start = od->pos + od->len; while (true) {
if (start >= od->buffer_size) dest = fifo_buffer_write(od->buffer, &max_length);
start -= od->buffer_size; if (dest != NULL)
break;
nbytes = start < od->pos
? od->pos - start
: od->buffer_size - start;
assert(nbytes > 0); /* wait for some free space in the buffer */
g_cond_wait(od->condition, od->mutex);
}
if (nbytes > size) if (size > max_length)
nbytes = size; size = max_length;
memcpy(od->buffer + start, chunk, nbytes); memcpy(dest, chunk, size);
od->len += nbytes; fifo_buffer_append(od->buffer, size);
g_mutex_unlock(od->mutex); g_mutex_unlock(od->mutex);
return nbytes; return size;
} }
const struct audio_output_plugin osx_output_plugin = { const struct audio_output_plugin osx_output_plugin = {
......
...@@ -202,7 +202,7 @@ recorder_output_close(struct audio_output *ao) ...@@ -202,7 +202,7 @@ recorder_output_close(struct audio_output *ao)
/* flush the encoder and write the rest to the file */ /* flush the encoder and write the rest to the file */
if (encoder_flush(recorder->encoder, NULL)) if (encoder_end(recorder->encoder, NULL))
recorder_output_encoder_to_file(recorder, NULL); recorder_output_encoder_to_file(recorder, NULL);
/* now really close everything */ /* now really close everything */
......
...@@ -376,7 +376,7 @@ static void close_shout_conn(struct shout_data * sd) ...@@ -376,7 +376,7 @@ static void close_shout_conn(struct shout_data * sd)
sd->buf.len = 0; sd->buf.len = 0;
if (sd->encoder != NULL) { if (sd->encoder != NULL) {
if (encoder_flush(sd->encoder, NULL)) if (encoder_end(sd->encoder, NULL))
write_page(sd, NULL); write_page(sd, NULL);
encoder_close(sd->encoder); encoder_close(sd->encoder);
......
...@@ -50,7 +50,7 @@ song_remove_event(void) ...@@ -50,7 +50,7 @@ song_remove_event(void)
assert(removed_song != NULL); assert(removed_song != NULL);
uri = song_get_uri(removed_song); uri = song_get_uri(removed_song);
g_debug("removing: %s", uri); g_message("removing %s", uri);
g_free(uri); g_free(uri);
#ifdef ENABLE_SQLITE #ifdef ENABLE_SQLITE
......
...@@ -676,6 +676,9 @@ directory_make_child_checked(struct directory *parent, const char *name_utf8) ...@@ -676,6 +676,9 @@ directory_make_child_checked(struct directory *parent, const char *name_utf8)
inodeFoundInParent(parent, st.st_ino, st.st_dev)) inodeFoundInParent(parent, st.st_ino, st.st_dev))
return NULL; return NULL;
if (skip_symlink(parent, name_utf8))
return NULL;
/* if we're adding directory paths, make sure to delete filenames /* if we're adding directory paths, make sure to delete filenames
with potentially the same name */ with potentially the same name */
db_lock(); db_lock();
...@@ -728,7 +731,8 @@ updatePath(const char *path) ...@@ -728,7 +731,8 @@ updatePath(const char *path)
name = g_path_get_basename(path); name = g_path_get_basename(path);
if (stat_directory_child(parent, name, &st) == 0) if (!skip_symlink(parent, name) &&
stat_directory_child(parent, name, &st) == 0)
updateInDirectory(parent, name, &st); updateInDirectory(parent, name, &st);
else else
modified |= delete_name_in(parent, name); modified |= delete_name_in(parent, name);
......
...@@ -34,13 +34,13 @@ bool uri_has_scheme(const char *uri) ...@@ -34,13 +34,13 @@ bool uri_has_scheme(const char *uri)
const char * const char *
uri_get_suffix(const char *uri) uri_get_suffix(const char *uri)
{ {
const char *suffix = strrchr(g_basename(uri), '.'); const char *suffix = strrchr(uri, '.');
if (suffix == NULL) if (suffix == NULL)
return NULL; return NULL;
++suffix; ++suffix;
if (strchr(suffix, '/') != NULL) if (strpbrk(suffix, "/\\") != NULL)
return NULL; return NULL;
return suffix; return suffix;
......
...@@ -121,7 +121,7 @@ int main(int argc, char **argv) ...@@ -121,7 +121,7 @@ int main(int argc, char **argv)
encoder_to_stdout(encoder); encoder_to_stdout(encoder);
} }
ret = encoder_flush(encoder, &error); ret = encoder_end(encoder, &error);
if (!ret) { if (!ret) {
g_printerr("encoder_flush() failed: %s\n", g_printerr("encoder_flush() failed: %s\n",
error->message); error->message);
......
/*
* Copyright (C) 2003-2012 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "encoder_list.h"
#include "encoder_plugin.h"
#include "audio_format.h"
#include "conf.h"
#include "stdbin.h"
#include "tag.h"
#include <glib.h>
#include <stddef.h>
#include <unistd.h>
static uint8_t zero[256];
static void
encoder_to_stdout(struct encoder *encoder)
{
size_t length;
static char buffer[32768];
while ((length = encoder_read(encoder, buffer, sizeof(buffer))) > 0) {
G_GNUC_UNUSED ssize_t ignored = write(1, buffer, length);
}
}
int
main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
{
G_GNUC_UNUSED bool success;
/* create the encoder */
const struct encoder_plugin *plugin = encoder_plugin_get("vorbis");
assert(plugin != NULL);
struct config_param *param = config_new_param(NULL, -1);
config_add_block_param(param, "quality", "5.0", -1);
struct encoder *encoder = encoder_init(plugin, param, NULL);
assert(encoder != NULL);
/* open the encoder */
struct audio_format audio_format;
audio_format_init(&audio_format, 44100, SAMPLE_FORMAT_S16, 2);
success = encoder_open(encoder, &audio_format, NULL);
assert(success);
/* write a block of data */
success = encoder_write(encoder, zero, sizeof(zero), NULL);
assert(success);
encoder_to_stdout(encoder);
/* write a tag */
success = encoder_pre_tag(encoder, NULL);
assert(success);
encoder_to_stdout(encoder);
struct tag *tag = tag_new();
tag_add_item(tag, TAG_ARTIST, "Foo");
tag_add_item(tag, TAG_TITLE, "Bar");
success = encoder_tag(encoder, tag, NULL);
assert(success);
tag_free(tag);
encoder_to_stdout(encoder);
/* write another block of data */
success = encoder_write(encoder, zero, sizeof(zero), NULL);
assert(success);
/* finish */
success = encoder_end(encoder, NULL);
assert(success);
encoder_to_stdout(encoder);
encoder_close(encoder);
encoder_finish(encoder);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment