Mercurial > audlegacy-plugins
view src/esd/audio.c @ 2284:d19b53359b24
cleaned up the sndfile wav plugin, currently limiting it ONLY TO WAV
PLAYBACK. if somebody is more experienced with it and wants to restore
the other formats, go ahead (maybe change the name of the plugin too?).
author | mf0102 <0102@gmx.at> |
---|---|
date | Wed, 09 Jan 2008 15:41:22 +0100 |
parents | 2e8adf61c54f |
children | ca1a9bd5f311 |
line wrap: on
line source
/* BMP - Cross-platform multimedia player * Copyright (C) 2003-2004 BMP development team. * * Based on XMMS: * Copyright (C) 1998-2003 XMMS development team. * * 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 <glib.h> #include <stdlib.h> #include <string.h> #include <esd.h> #include <unistd.h> #include <audacious/util.h> #include "esdout.h" static gint fd = 0; static gpointer buffer; static gboolean going = FALSE, paused = FALSE, prebuffer, remove_prebuffer; static gint buffer_size, prebuffer_size, blk_size = 4096; static gint rd_index = 0, wr_index = 0; static gint output_time_offset = 0; static guint64 written = 0, output_bytes = 0; static gint bps, ebps; static gint flush; static gint format, channels, frequency, latency; static esd_format_t esd_format; static gint input_bps, input_format, input_frequency, input_channels; static GThread *buffer_thread; static void *(*esd_translate) (void *, gint); static int player_id_unique = 0; static gint get_latency(void) { int fd, amount = 0; #ifndef HAVE_ESD_GET_LATENCY esd_server_info_t *info; #endif fd = esd_open_sound(esd_cfg.hostname); if (fd == -1) return 0; #ifdef HAVE_ESD_GET_LATENCY amount = esd_get_latency(fd); #else info = esd_get_server_info(fd); if (info) { if (info->format & ESD_STEREO) { if (info->format & ESD_BITS16) amount = (44100 * (ESD_BUF_SIZE + 64)) / info->rate; else amount = (44100 * (ESD_BUF_SIZE + 128)) / info->rate; } else { if (info->format & ESD_BITS16) amount = (2 * 44100 * (ESD_BUF_SIZE + 128)) / info->rate; else amount = (2 * 44100 * (ESD_BUF_SIZE + 256)) / info->rate; } free(info); } amount += ESD_BUF_SIZE * 2; #endif esd_close(fd); return amount; } static void * esd_stou8(void *data, gint length) { int len = length; unsigned char *dat = (unsigned char *) data; while (len-- > 0) *dat++ ^= 0x80; return data; } static void * esd_utos16sw(void *data, gint length) { int len = length; short *dat = data; while (len > 0) { *dat = GUINT16_SWAP_LE_BE(*dat) ^ 0x8000; dat++; len -= 2; } return data; } static void * esd_utos16(void *data, gint length) { int len = length; short *dat = data; while (len > 0) { *dat ^= 0x8000; dat++; len -= 2; } return data; } static void * esd_16sw(void *data, gint length) { int len = length; short *dat = data; while (len > 0) { *dat = GUINT16_SWAP_LE_BE(*dat); dat++; len -= 2; } return data; } static void esdout_setup_format(AFormat fmt, gint rate, gint nch) { gboolean swap_sign = FALSE; gboolean swap_16 = FALSE; format = fmt; frequency = rate; channels = nch; switch (fmt) { case FMT_S8: swap_sign = TRUE; case FMT_U8: esd_format = ESD_BITS8; break; case FMT_U16_LE: case FMT_U16_BE: case FMT_U16_NE: swap_sign = TRUE; case FMT_S16_LE: case FMT_S16_BE: case FMT_S16_NE: esd_format = ESD_BITS16; break; } #if (G_BYTE_ORDER == G_BIG_ENDIAN) if (fmt == FMT_U16_LE || fmt == FMT_S16_LE) #else if (fmt == FMT_U16_BE || fmt == FMT_S16_BE) #endif swap_16 = TRUE; esd_translate = (void *(*)()) NULL; if (esd_format == ESD_BITS8) { if (swap_sign == TRUE) esd_translate = esd_stou8; } else { if (swap_sign == TRUE) { if (swap_16 == TRUE) esd_translate = esd_utos16sw; else esd_translate = esd_utos16; } else { if (swap_16 == TRUE) esd_translate = esd_16sw; } } bps = rate * nch; if (esd_format == ESD_BITS16) bps *= 2; if (nch == 1) esd_format |= ESD_MONO; else esd_format |= ESD_STEREO; esd_format |= ESD_STREAM | ESD_PLAY; latency = ((get_latency() * frequency) / 44100) * channels; if (format != FMT_U8 && format != FMT_S8) latency *= 2; } gint esdout_get_written_time(void) { if (!going) return 0; return (gint) ((written * 1000) / input_bps); } gint esdout_get_output_time(void) { guint64 bytes; if (!fd || !going) return 0; bytes = output_bytes; if (!paused) bytes -= (bytes < latency ? bytes : latency); return output_time_offset + (gint) ((bytes * 1000) / ebps); } gint esdout_used(void) { if (wr_index >= rd_index) return wr_index - rd_index; return buffer_size - (rd_index - wr_index); } gint esdout_playing(void) { if (!going) return FALSE; if (!esdout_used()) return FALSE; return TRUE; } gint esdout_free(void) { if (remove_prebuffer && prebuffer) { prebuffer = FALSE; remove_prebuffer = FALSE; } if (prebuffer) remove_prebuffer = TRUE; if (rd_index > wr_index) return (rd_index - wr_index) - 1; return (buffer_size - (wr_index - rd_index)) - 1; } static void esdout_write_audio(gpointer data, gint length) { while (length > 0) { int num_written; if (esd_translate) num_written = write(fd, esd_translate(data, length), length); else num_written = write(fd, data, length); if (num_written <= 0) break; length -= num_written; data += num_written; output_bytes += num_written; } } void esdout_write(gpointer ptr, gint length) { gint cnt, off = 0; remove_prebuffer = FALSE; written += length; while (length > 0) { cnt = MIN(length, buffer_size - wr_index); memcpy((gchar *) buffer + wr_index, (gchar *) ptr + off, cnt); wr_index = (wr_index + cnt) % buffer_size; length -= cnt; off += cnt; } } void esdout_close(void) { if (!going) return; going = 0; g_thread_join(buffer_thread); wr_index = 0; rd_index = 0; g_free(esd_cfg.playername); esd_cfg.playername = NULL; } void esdout_flush(gint time) { flush = time; while (flush != -1) g_usleep(10000); } void esdout_pause(short p) { paused = p; } gpointer esdout_loop(gpointer arg) { gint length, cnt; while (going) { if (esdout_used() > prebuffer_size) prebuffer = FALSE; if (esdout_used() > 0 && !paused && !prebuffer) { length = MIN(blk_size, esdout_used()); while (length > 0) { cnt = MIN(length, buffer_size - rd_index); esdout_write_audio((gchar *) buffer + rd_index, cnt); rd_index = (rd_index + cnt) % buffer_size; length -= cnt; } } else g_usleep(10000); if (flush != -1) { output_time_offset = flush; written = (guint64) (flush / 10) * (guint64) (input_bps / 100); rd_index = wr_index = output_bytes = 0; flush = -1; prebuffer = TRUE; } } esd_close(fd); g_free(buffer); return NULL; } void esdout_set_audio_params(void) { fd = esd_play_stream(esd_format, frequency, esd_cfg.hostname, esd_cfg.playername); /* Set the stream's mixer */ if (fd != -1) esdout_mixer_init(); ebps = frequency * channels; if (format == FMT_U16_BE || format == FMT_U16_LE || format == FMT_S16_BE || format == FMT_S16_LE || format == FMT_S16_NE || format == FMT_U16_NE) ebps *= 2; } gint esdout_open(AFormat fmt, gint rate, gint nch) { esdout_setup_format(fmt, rate, nch); input_format = format; input_channels = channels; input_frequency = frequency; input_bps = bps; buffer_size = (esd_cfg.buffer_size * input_bps) / 1000; if (buffer_size < 8192) buffer_size = 8192; prebuffer_size = (buffer_size * esd_cfg.prebuffer) / 100; if (buffer_size - prebuffer_size < 4096) prebuffer_size = buffer_size - 4096; buffer = g_malloc0(buffer_size); flush = -1; prebuffer = 1; wr_index = rd_index = output_time_offset = written = output_bytes = 0; paused = FALSE; remove_prebuffer = FALSE; esd_cfg.playername = g_strdup_printf("xmms - plugin (%d) [%d]", getpid(), player_id_unique++); if (esd_cfg.hostname) g_free(esd_cfg.hostname); if (esd_cfg.use_remote) esd_cfg.hostname = g_strdup_printf("%s:%d", esd_cfg.server, esd_cfg.port); else esd_cfg.hostname = NULL; esdout_set_audio_params(); if (fd == -1) { g_free(esd_cfg.playername); esd_cfg.playername = NULL; g_free(buffer); return 0; } going = 1; buffer_thread = g_thread_create(esdout_loop, NULL, TRUE, NULL); return 1; } void esdout_tell(AFormat * fmt, gint * rate, gint * nch) { (*fmt) = format; (*rate) = frequency; (*nch) = channels; }