Merge branch 'v0.16.x'
Conflicts: src/output/osx_plugin.c src/text_input_stream.c
This commit is contained in:
@@ -86,7 +86,15 @@ directory_delete(struct directory *directory)
|
||||
const char *
|
||||
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 *
|
||||
|
@@ -354,6 +354,7 @@ const struct encoder_plugin flac_encoder_plugin = {
|
||||
.finish = flac_encoder_finish,
|
||||
.open = flac_encoder_open,
|
||||
.close = flac_encoder_close,
|
||||
.end = flac_encoder_flush,
|
||||
.flush = flac_encoder_flush,
|
||||
.write = flac_encoder_write,
|
||||
.read = flac_encoder_read,
|
||||
|
@@ -300,6 +300,7 @@ const struct encoder_plugin twolame_encoder_plugin = {
|
||||
.finish = twolame_encoder_finish,
|
||||
.open = twolame_encoder_open,
|
||||
.close = twolame_encoder_close,
|
||||
.end = twolame_encoder_flush,
|
||||
.flush = twolame_encoder_flush,
|
||||
.write = twolame_encoder_write,
|
||||
.read = twolame_encoder_read,
|
||||
|
@@ -285,8 +285,6 @@ vorbis_encoder_pre_tag(struct encoder *_encoder, G_GNUC_UNUSED GError **error)
|
||||
vorbis_analysis_init(&encoder->vd, &encoder->vi);
|
||||
vorbis_block_init(&encoder->vd, &encoder->vb);
|
||||
|
||||
ogg_stream_reset(&encoder->os);
|
||||
|
||||
encoder->flush = true;
|
||||
return true;
|
||||
}
|
||||
@@ -407,6 +405,7 @@ const struct encoder_plugin vorbis_encoder_plugin = {
|
||||
.finish = vorbis_encoder_finish,
|
||||
.open = vorbis_encoder_open,
|
||||
.close = vorbis_encoder_close,
|
||||
.end = vorbis_encoder_pre_tag,
|
||||
.flush = vorbis_encoder_flush,
|
||||
.pre_tag = vorbis_encoder_pre_tag,
|
||||
.tag = vorbis_encoder_tag,
|
||||
|
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -32,6 +33,10 @@ struct tag;
|
||||
|
||||
struct encoder {
|
||||
const struct encoder_plugin *plugin;
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool open, pre_tag, tag, end;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct encoder_plugin {
|
||||
@@ -48,6 +53,8 @@ struct encoder_plugin {
|
||||
|
||||
void (*close)(struct encoder *encoder);
|
||||
|
||||
bool (*end)(struct encoder *encoder, GError **error);
|
||||
|
||||
bool (*flush)(struct encoder *encoder, GError **error);
|
||||
|
||||
bool (*pre_tag)(struct encoder *encoder, GError **error);
|
||||
@@ -73,6 +80,10 @@ encoder_struct_init(struct encoder *encoder,
|
||||
const struct encoder_plugin *plugin)
|
||||
{
|
||||
encoder->plugin = plugin;
|
||||
|
||||
#ifndef NDEBUG
|
||||
encoder->open = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,6 +109,8 @@ encoder_init(const struct encoder_plugin *plugin,
|
||||
static inline void
|
||||
encoder_finish(struct encoder *encoder)
|
||||
{
|
||||
assert(!encoder->open);
|
||||
|
||||
encoder->plugin->finish(encoder);
|
||||
}
|
||||
|
||||
@@ -116,7 +129,14 @@ static inline bool
|
||||
encoder_open(struct encoder *encoder, struct audio_format *audio_format,
|
||||
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,
|
||||
static inline void
|
||||
encoder_close(struct encoder *encoder)
|
||||
{
|
||||
assert(encoder->open);
|
||||
|
||||
if (encoder->plugin->close != NULL)
|
||||
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)
|
||||
static inline bool
|
||||
encoder_flush(struct encoder *encoder, GError **error)
|
||||
{
|
||||
assert(encoder->open);
|
||||
assert(!encoder->pre_tag);
|
||||
assert(!encoder->tag);
|
||||
assert(!encoder->end);
|
||||
|
||||
/* this method is optional */
|
||||
return encoder->plugin->flush != NULL
|
||||
? encoder->plugin->flush(encoder, error)
|
||||
@@ -162,10 +222,20 @@ encoder_flush(struct encoder *encoder, GError **error)
|
||||
static inline bool
|
||||
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 */
|
||||
return encoder->plugin->pre_tag != NULL
|
||||
bool success = encoder->plugin->pre_tag != NULL
|
||||
? encoder->plugin->pre_tag(encoder, error)
|
||||
: true;
|
||||
|
||||
#ifndef NDEBUG
|
||||
encoder->pre_tag = success;
|
||||
#endif
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,6 +252,15 @@ encoder_pre_tag(struct encoder *encoder, GError **error)
|
||||
static inline bool
|
||||
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 */
|
||||
return encoder->plugin->tag != NULL
|
||||
? encoder->plugin->tag(encoder, tag, error)
|
||||
@@ -201,6 +280,11 @@ static inline bool
|
||||
encoder_write(struct encoder *encoder, const void *data, size_t length,
|
||||
GError **error)
|
||||
{
|
||||
assert(encoder->open);
|
||||
assert(!encoder->pre_tag);
|
||||
assert(!encoder->tag);
|
||||
assert(!encoder->end);
|
||||
|
||||
return encoder->plugin->write(encoder, data, length, error);
|
||||
}
|
||||
|
||||
@@ -215,6 +299,16 @@ encoder_write(struct encoder *encoder, const void *data, size_t length,
|
||||
static inline size_t
|
||||
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);
|
||||
}
|
||||
|
||||
|
@@ -146,6 +146,13 @@ mpd_jack_process(jack_nframes_t nframes, void *arg)
|
||||
|
||||
for (unsigned i = 0; i < jd->audio_format.channels; ++i) {
|
||||
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],
|
||||
(char *)out, available * jack_sample_size);
|
||||
|
||||
@@ -159,6 +166,12 @@ mpd_jack_process(jack_nframes_t nframes, void *arg)
|
||||
for (unsigned i = jd->audio_format.channels;
|
||||
i < jd->num_source_ports; ++i) {
|
||||
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)
|
||||
out[f] = 0.0;
|
||||
@@ -572,6 +585,9 @@ mpd_jack_open(struct audio_output *ao, struct audio_format *audio_format,
|
||||
|
||||
jd->pause = false;
|
||||
|
||||
if (jd->client != NULL && jd->shutdown)
|
||||
mpd_jack_disconnect(jd);
|
||||
|
||||
if (jd->client == NULL && !mpd_jack_connect(jd, error_r))
|
||||
return false;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2011 The Music Player Daemon Project
|
||||
* 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
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "config.h"
|
||||
#include "osx_output_plugin.h"
|
||||
#include "output_api.h"
|
||||
#include "fifo_buffer.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
@@ -40,10 +41,8 @@ struct osx_output {
|
||||
AudioUnit au;
|
||||
GMutex *mutex;
|
||||
GCond *condition;
|
||||
char *buffer;
|
||||
size_t buffer_size;
|
||||
size_t pos;
|
||||
size_t len;
|
||||
|
||||
struct fifo_buffer *buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -96,11 +95,6 @@ osx_output_init(const struct config_param *param, GError **error_r)
|
||||
oo->mutex = g_mutex_new();
|
||||
oo->condition = g_cond_new();
|
||||
|
||||
oo->pos = 0;
|
||||
oo->len = 0;
|
||||
oo->buffer = NULL;
|
||||
oo->buffer_size = 0;
|
||||
|
||||
return &oo->base;
|
||||
}
|
||||
|
||||
@@ -109,7 +103,6 @@ osx_output_finish(struct audio_output *ao)
|
||||
{
|
||||
struct osx_output *od = (struct osx_output *)ao;
|
||||
|
||||
g_free(od->buffer);
|
||||
g_mutex_free(od->mutex);
|
||||
g_cond_free(od->condition);
|
||||
g_free(od);
|
||||
@@ -215,37 +208,29 @@ osx_render(void *vdata,
|
||||
struct osx_output *od = (struct osx_output *) vdata;
|
||||
AudioBuffer *buffer = &buffer_list->mBuffers[0];
|
||||
size_t buffer_size = buffer->mDataByteSize;
|
||||
size_t bytes_to_copy;
|
||||
size_t trailer_length;
|
||||
size_t dest_pos = 0;
|
||||
|
||||
assert(od->buffer != NULL);
|
||||
|
||||
g_mutex_lock(od->mutex);
|
||||
|
||||
bytes_to_copy = MIN(od->len, buffer_size);
|
||||
od->len -= bytes_to_copy;
|
||||
size_t nbytes;
|
||||
const void *src = fifo_buffer_read(od->buffer, &nbytes);
|
||||
|
||||
trailer_length = od->buffer_size - od->pos;
|
||||
if (bytes_to_copy > trailer_length) {
|
||||
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;
|
||||
}
|
||||
if (src != NULL) {
|
||||
if (nbytes > buffer_size)
|
||||
nbytes = buffer_size;
|
||||
|
||||
memcpy((unsigned char*)buffer->mData + dest_pos,
|
||||
od->buffer + od->pos, bytes_to_copy);
|
||||
od->pos += bytes_to_copy;
|
||||
|
||||
if (od->pos >= od->buffer_size)
|
||||
od->pos = 0;
|
||||
memcpy(buffer->mData, src, nbytes);
|
||||
fifo_buffer_consume(od->buffer, nbytes);
|
||||
} else
|
||||
nbytes = 0;
|
||||
|
||||
g_cond_signal(od->condition);
|
||||
g_mutex_unlock(od->mutex);
|
||||
|
||||
if (bytes_to_copy < buffer_size)
|
||||
memset((unsigned char*)buffer->mData + bytes_to_copy, 0,
|
||||
buffer_size - bytes_to_copy);
|
||||
if (nbytes < buffer_size)
|
||||
memset((unsigned char*)buffer->mData + nbytes, 0,
|
||||
buffer_size - nbytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -315,7 +300,7 @@ osx_output_cancel(struct audio_output *ao)
|
||||
struct osx_output *od = (struct osx_output *)ao;
|
||||
|
||||
g_mutex_lock(od->mutex);
|
||||
od->len = 0;
|
||||
fifo_buffer_clear(od->buffer);
|
||||
g_mutex_unlock(od->mutex);
|
||||
}
|
||||
|
||||
@@ -326,6 +311,8 @@ osx_output_close(struct audio_output *ao)
|
||||
|
||||
AudioOutputUnitStop(od->au);
|
||||
AudioUnitUninitialize(od->au);
|
||||
|
||||
fifo_buffer_free(od->buffer);
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -387,12 +374,8 @@ osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GErr
|
||||
}
|
||||
|
||||
/* create a buffer of 1s */
|
||||
od->buffer_size = (audio_format->sample_rate) *
|
||||
audio_format_frame_size(audio_format);
|
||||
od->buffer = g_realloc(od->buffer, od->buffer_size);
|
||||
|
||||
od->pos = 0;
|
||||
od->len = 0;
|
||||
od->buffer = fifo_buffer_new(audio_format->sample_rate *
|
||||
audio_format_frame_size(audio_format));
|
||||
|
||||
status = AudioOutputUnitStart(od->au);
|
||||
if (status != 0) {
|
||||
@@ -411,33 +394,30 @@ osx_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
G_GNUC_UNUSED GError **error)
|
||||
{
|
||||
struct osx_output *od = (struct osx_output *)ao;
|
||||
size_t start, nbytes;
|
||||
|
||||
g_mutex_lock(od->mutex);
|
||||
|
||||
while (od->len >= od->buffer_size)
|
||||
void *dest;
|
||||
size_t max_length;
|
||||
|
||||
while (true) {
|
||||
dest = fifo_buffer_write(od->buffer, &max_length);
|
||||
if (dest != NULL)
|
||||
break;
|
||||
|
||||
/* wait for some free space in the buffer */
|
||||
g_cond_wait(od->condition, od->mutex);
|
||||
}
|
||||
|
||||
start = od->pos + od->len;
|
||||
if (start >= od->buffer_size)
|
||||
start -= od->buffer_size;
|
||||
if (size > max_length)
|
||||
size = max_length;
|
||||
|
||||
nbytes = start < od->pos
|
||||
? od->pos - start
|
||||
: od->buffer_size - start;
|
||||
|
||||
assert(nbytes > 0);
|
||||
|
||||
if (nbytes > size)
|
||||
nbytes = size;
|
||||
|
||||
memcpy(od->buffer + start, chunk, nbytes);
|
||||
od->len += nbytes;
|
||||
memcpy(dest, chunk, size);
|
||||
fifo_buffer_append(od->buffer, size);
|
||||
|
||||
g_mutex_unlock(od->mutex);
|
||||
|
||||
return nbytes;
|
||||
return size;
|
||||
}
|
||||
|
||||
const struct audio_output_plugin osx_output_plugin = {
|
||||
|
@@ -202,7 +202,7 @@ recorder_output_close(struct audio_output *ao)
|
||||
|
||||
/* 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);
|
||||
|
||||
/* now really close everything */
|
||||
|
@@ -376,7 +376,7 @@ static void close_shout_conn(struct shout_data * sd)
|
||||
sd->buf.len = 0;
|
||||
|
||||
if (sd->encoder != NULL) {
|
||||
if (encoder_flush(sd->encoder, NULL))
|
||||
if (encoder_end(sd->encoder, NULL))
|
||||
write_page(sd, NULL);
|
||||
|
||||
encoder_close(sd->encoder);
|
||||
|
@@ -50,7 +50,7 @@ song_remove_event(void)
|
||||
assert(removed_song != NULL);
|
||||
|
||||
uri = song_get_uri(removed_song);
|
||||
g_debug("removing: %s", uri);
|
||||
g_message("removing %s", uri);
|
||||
g_free(uri);
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
|
@@ -676,6 +676,9 @@ directory_make_child_checked(struct directory *parent, const char *name_utf8)
|
||||
inodeFoundInParent(parent, st.st_ino, st.st_dev))
|
||||
return NULL;
|
||||
|
||||
if (skip_symlink(parent, name_utf8))
|
||||
return NULL;
|
||||
|
||||
/* if we're adding directory paths, make sure to delete filenames
|
||||
with potentially the same name */
|
||||
db_lock();
|
||||
@@ -728,7 +731,8 @@ updatePath(const char *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);
|
||||
else
|
||||
modified |= delete_name_in(parent, name);
|
||||
|
@@ -34,13 +34,13 @@ bool uri_has_scheme(const char *uri)
|
||||
const char *
|
||||
uri_get_suffix(const char *uri)
|
||||
{
|
||||
const char *suffix = strrchr(g_basename(uri), '.');
|
||||
const char *suffix = strrchr(uri, '.');
|
||||
if (suffix == NULL)
|
||||
return NULL;
|
||||
|
||||
++suffix;
|
||||
|
||||
if (strchr(suffix, '/') != NULL)
|
||||
if (strpbrk(suffix, "/\\") != NULL)
|
||||
return NULL;
|
||||
|
||||
return suffix;
|
||||
|
Reference in New Issue
Block a user