Interface implementation example: OSS mixer. Also osscommon->osselement so it can be loaded without being a source/si...

Original commit message from CVS:
Interface implementation example: OSS mixer. Also osscommon->osselement so it can be loaded without being a source/sink (for a stand-alone mixer)
This commit is contained in:
Ronald S. Bultje 2003-09-13 01:22:59 +00:00
parent adda650f23
commit 96fc83aeac
10 changed files with 1249 additions and 173 deletions

View file

@ -3,11 +3,12 @@ plugin_LTLIBRARIES = libgstossaudio.la
EXTRA_LTLIBRARIES = libgstosshelper.la EXTRA_LTLIBRARIES = libgstosshelper.la
libgstossaudio_la_SOURCES = gstosssink.c \ libgstossaudio_la_SOURCES = gstossaudio.c \
gstosselement.c \
gstossmixer.c \
gstosssink.c \
gstosssrc.c \ gstosssrc.c \
gstossaudio.c \ gstossgst.c
gstossgst.c \
gstosscommon.c
libgstossaudio_la_CFLAGS = $(GST_CFLAGS) libgstossaudio_la_CFLAGS = $(GST_CFLAGS)
libgstossaudio_la_LIBADD = libgstossaudio_la_LIBADD =
@ -16,4 +17,9 @@ libgstossaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstosshelper_la_SOURCES = gstosshelper.c libgstosshelper_la_SOURCES = gstosshelper.c
libgstosshelper_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstosshelper_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = gstosssink.h gstosssrc.h gstossgst.h gstosshelper.h gstosscommon.h noinst_HEADERS = gstosssink.h \
gstosssrc.h \
gstossgst.h \
gstosshelper.h \
gstosselement.h \
gstossmixer.c

View file

@ -17,7 +17,11 @@
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstosselement.h"
#include "gstosssink.h" #include "gstosssink.h"
#include "gstosssrc.h" #include "gstosssrc.h"
#include "gstossgst.h" #include "gstossgst.h"
@ -25,19 +29,16 @@
static gboolean static gboolean
plugin_init (GModule *module, GstPlugin *plugin) plugin_init (GModule *module, GstPlugin *plugin)
{ {
gboolean ret;
if (!gst_library_load ("gstaudio")) if (!gst_library_load ("gstaudio"))
return FALSE; return FALSE;
ret = gst_osssink_factory_init (plugin); if (!gst_osselement_factory_init (plugin) ||
g_return_val_if_fail (ret == TRUE, FALSE); !gst_osssrc_factory_init (plugin) ||
!gst_osssink_factory_init (plugin) ||
ret = gst_osssrc_factory_init (plugin); !gst_ossgst_factory_init (plugin)) {
g_return_val_if_fail (ret == TRUE, FALSE); g_warning ("Failed to register OSS elements!");
return FALSE;
ret = gst_ossgst_factory_init (plugin); }
g_return_val_if_fail (ret == TRUE, FALSE);
return TRUE; return TRUE;
} }

681
sys/oss/gstosselement.c Normal file
View file

@ -0,0 +1,681 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
*
* gstosssink.c:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/soundcard.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "gstosselement.h"
#include "gstossmixer.h"
enum {
ARG_0,
ARG_DEVICE,
ARG_MIXERDEV,
};
/* elementfactory information */
static GstElementDetails gst_osselement_details = {
"Audio Element (OSS)",
"Generic/Audio",
"LGPL",
"Generic OSS element",
VERSION,
"Erik Walthinsen <omega@cse.ogi.edu>",
"(C) 1999",
};
static void gst_osselement_class_init (GstOssElementClass *klass);
static void gst_osselement_init (GstOssElement *oss);
static void gst_osselement_dispose (GObject *object);
static void gst_osselement_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gst_osselement_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static GstElementStateReturn gst_osselement_change_state (GstElement *element);
static GstElementClass *parent_class = NULL;
/*static guint gst_osssrc_signals[LAST_SIGNAL] = { 0 }; */
GType
gst_osselement_get_type (void)
{
static GType osselement_type = 0;
if (!osselement_type) {
static const GTypeInfo osselement_info = {
sizeof(GstOssElementClass),
NULL,
NULL,
(GClassInitFunc)gst_osselement_class_init,
NULL,
NULL,
sizeof(GstOssElement),
0,
(GInstanceInitFunc)gst_osselement_init,
};
static const GInterfaceInfo ossiface_info = {
(GInterfaceInitFunc) gst_oss_interface_init,
NULL,
NULL,
};
static const GInterfaceInfo ossmixer_info = {
(GInterfaceInitFunc) gst_ossmixer_interface_init,
NULL,
NULL,
};
osselement_type = g_type_register_static (GST_TYPE_ELEMENT,
"GstOssElement",
&osselement_info, 0);
g_type_add_interface_static (osselement_type,
GST_TYPE_INTERFACE,
&ossiface_info);
g_type_add_interface_static (osselement_type,
GST_TYPE_MIXER,
&ossmixer_info);
}
return osselement_type;
}
static void
gst_osselement_class_init (GstOssElementClass *klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
g_param_spec_string ("device", "device", "oss device (/dev/dspN usually)",
"default", G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MIXERDEV,
g_param_spec_string ("mixerdev", "mixer device",
"oss mixer device (/dev/mixerN usually)",
"default", G_PARAM_READWRITE));
gobject_class->set_property = gst_osselement_set_property;
gobject_class->get_property = gst_osselement_get_property;
gobject_class->dispose = gst_osselement_dispose;
gstelement_class->change_state = gst_osselement_change_state;
}
static void
gst_osselement_init (GstOssElement *oss)
{
oss->device = g_strdup ("/dev/dsp");
oss->mixer_dev = g_strdup ("/dev/mixer");
oss->fd = -1;
oss->mixer_fd = -1;
oss->channellist = NULL;
gst_osselement_reset (oss);
}
static void
gst_osselement_dispose (GObject *object)
{
GstOssElement *oss = (GstOssElement *) object;
g_free (oss->device);
g_free (oss->mixer_dev);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
void
gst_osselement_reset (GstOssElement *oss)
{
oss->law = 0;
oss->endianness = G_BYTE_ORDER;
oss->sign = TRUE;
oss->width = 16;
oss->depth = 16;
oss->channels = 2;
oss->rate = 44100;
oss->fragment = 6;
oss->bps = 0;
/* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */
#ifdef WORDS_BIGENDIAN
oss->format = AFMT_S16_BE;
#else
oss->format = AFMT_S16_LE;
#endif /* WORDS_BIGENDIAN */
}
static gboolean
gst_ossformat_get (gint law, gint endianness, gboolean sign, gint width, gint depth,
gint *format, gint *bps)
{
if (width != depth)
return FALSE;
*bps = 1;
if (law == 0) {
if (width == 16) {
if (sign == TRUE) {
if (endianness == G_LITTLE_ENDIAN) {
*format = AFMT_S16_LE;
GST_DEBUG (
"16 bit signed LE, no law (%d)", *format);
}
else if (endianness == G_BIG_ENDIAN) {
*format = AFMT_S16_BE;
GST_DEBUG (
"16 bit signed BE, no law (%d)", *format);
}
}
else {
if (endianness == G_LITTLE_ENDIAN) {
*format = AFMT_U16_LE;
GST_DEBUG (
"16 bit unsigned LE, no law (%d)", *format);
}
else if (endianness == G_BIG_ENDIAN) {
*format = AFMT_U16_BE;
GST_DEBUG (
"16 bit unsigned BE, no law (%d)", *format);
}
}
*bps = 2;
}
else if (width == 8) {
if (sign == TRUE) {
*format = AFMT_S8;
GST_DEBUG (
"8 bit signed, no law (%d)", *format);
}
else {
*format = AFMT_U8;
GST_DEBUG (
"8 bit unsigned, no law (%d)", *format);
}
*bps = 1;
}
} else if (law == 1) {
*format = AFMT_MU_LAW;
GST_DEBUG (
"mu law (%d)", *format);
} else if (law == 2) {
*format = AFMT_A_LAW;
GST_DEBUG (
"a law (%d)", *format);
} else {
g_critical ("unknown law");
return FALSE;
}
return TRUE;
}
gboolean
gst_osselement_parse_caps (GstOssElement *oss, GstCaps *caps)
{
gint bps, format;
gst_caps_get_int (caps, "width", &oss->width);
gst_caps_get_int (caps, "depth", &oss->depth);
if (oss->width != oss->depth)
return FALSE;
gst_caps_get_int (caps, "law", &oss->law);
gst_caps_get_int (caps, "endianness", &oss->endianness);
gst_caps_get_boolean (caps, "signed", &oss->sign);
if (!gst_ossformat_get (oss->law, oss->endianness, oss->sign,
oss->width, oss->depth, &format, &bps))
{
GST_DEBUG ("could not get format");
return FALSE;
}
gst_caps_get_int (caps, "channels", &oss->channels);
gst_caps_get_int (caps, "rate", &oss->rate);
oss->bps = bps * oss->channels * oss->rate;
oss->format = format;
return TRUE;
}
#define GET_FIXED_INT(caps, name, dest) \
G_STMT_START { \
if (gst_caps_has_fixed_property (caps, name)) \
gst_caps_get_int (caps, name, dest); \
} G_STMT_END
#define GET_FIXED_BOOLEAN(caps, name, dest) \
G_STMT_START { \
if (gst_caps_has_fixed_property (caps, name)) \
gst_caps_get_boolean (caps, name, dest); \
} G_STMT_END
gboolean
gst_osselement_merge_fixed_caps (GstOssElement *oss, GstCaps *caps)
{
gint bps, format;
/* peel off fixed stuff from the caps */
GET_FIXED_INT (caps, "law", &oss->law);
GET_FIXED_INT (caps, "endianness", &oss->endianness);
GET_FIXED_BOOLEAN (caps, "signed", &oss->sign);
GET_FIXED_INT (caps, "width", &oss->width);
GET_FIXED_INT (caps, "depth", &oss->depth);
if (!gst_ossformat_get (oss->law, oss->endianness, oss->sign,
oss->width, oss->depth, &format, &bps))
{
return FALSE;
}
GET_FIXED_INT (caps, "rate", &oss->rate);
GET_FIXED_INT (caps, "channels", &oss->channels);
oss->bps = bps * oss->channels * oss->rate;
oss->format = format;
return TRUE;
}
gboolean
gst_osselement_sync_parms (GstOssElement *oss)
{
audio_buf_info space;
int frag;
gint target_format;
gint target_channels;
gint target_rate;
gint fragscale, frag_ln;
if (oss->fd == -1)
return FALSE;
if (oss->fragment >> 16)
frag = oss->fragment;
else
frag = 0x7FFF0000 | oss->fragment;
GST_INFO ("osselement: setting sound card to %dHz %d format %s (%08x fragment)",
oss->rate, oss->format,
(oss->channels == 2) ? "stereo" : "mono", frag);
ioctl (oss->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
ioctl (oss->fd, SNDCTL_DSP_RESET, 0);
target_format = oss->format;
target_channels = oss->channels;
target_rate = oss->rate;
ioctl (oss->fd, SNDCTL_DSP_SETFMT, &oss->format);
ioctl (oss->fd, SNDCTL_DSP_CHANNELS, &oss->channels);
ioctl (oss->fd, SNDCTL_DSP_SPEED, &oss->rate);
ioctl (oss->fd, SNDCTL_DSP_GETBLKSIZE, &oss->fragment_size);
if (oss->mode == GST_OSSELEMENT_WRITE) {
ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &space);
}
else {
ioctl (oss->fd, SNDCTL_DSP_GETISPACE, &space);
}
/* calculate new fragment using a poor man's logarithm function */
fragscale = 1;
frag_ln = 0;
while (fragscale < space.fragsize) {
fragscale <<= 1;
frag_ln++;
}
oss->fragment = space.fragstotal << 16 | frag_ln;
GST_INFO ("osselement: set sound card to %dHz, %d format, %s "
"(%d bytes buffer, %08x fragment)",
oss->rate, oss->format,
(oss->channels == 2) ? "stereo" : "mono",
space.bytes, oss->fragment);
oss->fragment_time = (GST_SECOND * oss->fragment_size) / oss->bps;
GST_INFO ("fragment time %u %" G_GUINT64_FORMAT "\n",
oss->bps, oss->fragment_time);
if (target_format != oss->format ||
target_channels != oss->channels ||
target_rate != oss->rate)
{
g_warning ("couldn't set requested OSS parameters, enjoy the noise :)");
/* we could eventually return FALSE here, or just do some additional tests
* to see that the frequencies don't differ too much etc.. */
}
return TRUE;
}
static gboolean
gst_osselement_open_audio (GstOssElement *oss)
{
gint caps;
GstOssOpenMode mode = GST_OSSELEMENT_READ;
const GList *padlist;
g_return_val_if_fail (oss->fd == -1, FALSE);
GST_INFO ("osselement: attempting to open sound device");
/* Ok, so how do we open the device? We assume that we have (max.) one
* pad, and if this is a sinkpad, we're osssink (w). else, we're osssrc (r) */
padlist = gst_element_get_pad_list (GST_ELEMENT (oss));
if (padlist != NULL) {
GstPad *firstpad = padlist->data;
if (GST_PAD_IS_SINK (firstpad)) {
mode = GST_OSSELEMENT_WRITE;
}
}
/* first try to open the sound card */
if (mode == GST_OSSELEMENT_WRITE) {
/* open non blocking first so that it returns immediatly with an error
* when we cannot get to the device */
oss->fd = open (oss->device, O_WRONLY | O_NONBLOCK);
if (oss->fd >= 0) {
close (oss->fd);
/* re-open the sound device in blocking mode */
oss->fd = open (oss->device, O_WRONLY);
}
}
else {
oss->fd = open (oss->device, O_RDONLY);
}
if (oss->fd < 0) {
switch (errno) {
case EBUSY:
gst_element_error (GST_ELEMENT (oss),
"osselement: Unable to open %s (in use ?)",
oss->device);
break;
case EISDIR:
gst_element_error (GST_ELEMENT (oss),
"osselement: Device %s is a directory",
oss->device);
break;
case EACCES:
case ETXTBSY:
gst_element_error (GST_ELEMENT (oss),
"osselement: Cannot access %s, check permissions",
oss->device);
break;
case ENXIO:
case ENODEV:
case ENOENT:
gst_element_error (GST_ELEMENT (oss),
"osselement: Cannot access %s, does it exist ?",
oss->device);
break;
case EROFS:
gst_element_error (GST_ELEMENT (oss),
"osselement: Cannot access %s, read-only filesystem ?",
oss->device);
default:
/* FIXME: strerror is not threadsafe */
gst_element_error (GST_ELEMENT (oss),
"osselement: Cannot open %s, generic error: %s",
oss->device, strerror (errno));
break;
}
return FALSE;
}
oss->mode = mode;
/* we have it, set the default parameters and go have fun */
/* set card state */
ioctl (oss->fd, SNDCTL_DSP_GETCAPS, &caps);
GST_INFO ("osselement: Capabilities %08x", caps);
if (caps & DSP_CAP_DUPLEX) GST_INFO ( "osselement: Full duplex");
if (caps & DSP_CAP_REALTIME) GST_INFO ( "osselement: Realtime");
if (caps & DSP_CAP_BATCH) GST_INFO ( "osselement: Batch");
if (caps & DSP_CAP_COPROC) GST_INFO ( "osselement: Has coprocessor");
if (caps & DSP_CAP_TRIGGER) GST_INFO ( "osselement: Trigger");
if (caps & DSP_CAP_MMAP) GST_INFO ( "osselement: Direct access");
#ifdef DSP_CAP_MULTI
if (caps & DSP_CAP_MULTI) GST_INFO ( "osselement: Multiple open");
#endif /* DSP_CAP_MULTI */
#ifdef DSP_CAP_BIND
if (caps & DSP_CAP_BIND) GST_INFO ( "osselement: Channel binding");
#endif /* DSP_CAP_BIND */
ioctl(oss->fd, SNDCTL_DSP_GETFMTS, &caps);
GST_INFO ( "osselement: Formats %08x", caps);
if (caps & AFMT_MU_LAW) GST_INFO ( "osselement: MU_LAW");
if (caps & AFMT_A_LAW) GST_INFO ( "osselement: A_LAW");
if (caps & AFMT_IMA_ADPCM) GST_INFO ( "osselement: IMA_ADPCM");
if (caps & AFMT_U8) GST_INFO ( "osselement: U8");
if (caps & AFMT_S16_LE) GST_INFO ( "osselement: S16_LE");
if (caps & AFMT_S16_BE) GST_INFO ( "osselement: S16_BE");
if (caps & AFMT_S8) GST_INFO ( "osselement: S8");
if (caps & AFMT_U16_LE) GST_INFO ( "osselement: U16_LE");
if (caps & AFMT_U16_BE) GST_INFO ( "osselement: U16_BE");
if (caps & AFMT_MPEG) GST_INFO ( "osselement: MPEG");
#ifdef AFMT_AC3
if (caps & AFMT_AC3) GST_INFO ( "osselement: AC3");
#endif
GST_INFO ("osselement: opened audio (%s) with fd=%d",
oss->device, oss->fd);
oss->caps = caps;
gst_ossmixer_build_list (oss);
return TRUE;
}
static void
gst_osselement_close_audio (GstOssElement *oss)
{
if (oss->fd < 0)
return;
gst_ossmixer_free_list (oss);
close(oss->fd);
oss->fd = -1;
}
gboolean
gst_osselement_convert (GstOssElement *oss,
GstFormat src_format,
gint64 src_value,
GstFormat *dest_format,
gint64 *dest_value)
{
gboolean res = TRUE;
if (src_format == *dest_format) {
*dest_value = src_value;
return TRUE;
}
if (oss->bps == 0 || oss->channels == 0 || oss->width == 0)
return FALSE;
switch (src_format) {
case GST_FORMAT_BYTES:
switch (*dest_format) {
case GST_FORMAT_TIME:
*dest_value = src_value * GST_SECOND / oss->bps;
break;
case GST_FORMAT_DEFAULT:
*dest_value = src_value / (oss->channels * oss->width);
break;
default:
res = FALSE;
}
break;
case GST_FORMAT_TIME:
switch (*dest_format) {
case GST_FORMAT_BYTES:
*dest_value = src_value * oss->bps / GST_SECOND;
break;
case GST_FORMAT_DEFAULT:
*dest_value = src_value * oss->rate / GST_SECOND;
break;
default:
res = FALSE;
}
break;
case GST_FORMAT_DEFAULT:
switch (*dest_format) {
case GST_FORMAT_TIME:
*dest_value = src_value * GST_SECOND / oss->rate;
break;
case GST_FORMAT_BYTES:
*dest_value = src_value * oss->channels * oss->width;
break;
default:
res = FALSE;
}
break;
default:
res = FALSE;
}
return res;
}
static void
gst_osselement_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GstOssElement *oss = GST_OSSELEMENT (object);
switch (prop_id) {
case ARG_DEVICE:
/* disallow changing the device while it is opened
get_property("device") should return the right one */
if (gst_element_get_state (GST_ELEMENT (oss)) != GST_STATE_NULL) {
g_free (oss->device);
oss->device = g_strdup (g_value_get_string (value));
}
break;
case ARG_MIXERDEV:
/* disallow changing the device while it is opened
get_property("mixerdev") should return the right one */
if (gst_element_get_state (GST_ELEMENT (oss)) != GST_STATE_NULL) {
g_free (oss->mixer_dev);
oss->mixer_dev = g_strdup (g_value_get_string (value));
}
break;
default:
break;
}
}
static void
gst_osselement_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GstOssElement *oss = GST_OSSELEMENT (object);
switch (prop_id) {
case ARG_DEVICE:
g_value_set_string (value, oss->device);
break;
case ARG_MIXERDEV:
g_value_set_string (value, oss->mixer_dev);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstElementStateReturn
gst_osselement_change_state (GstElement *element)
{
GstOssElement *oss = GST_OSSELEMENT (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
if (!gst_osselement_open_audio (oss)) {
return GST_STATE_FAILURE;
}
GST_INFO ("osselement: opened sound device");
break;
case GST_STATE_READY_TO_NULL:
gst_osselement_close_audio (oss);
gst_osselement_reset (oss);
GST_INFO ("osselement: closed sound device");
break;
default:
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
}
gboolean
gst_osselement_factory_init (GstPlugin *plugin)
{
GstElementFactory *factory;
factory = gst_element_factory_new ("osselement",
GST_TYPE_OSSELEMENT,
&gst_osselement_details);
g_return_val_if_fail (factory != NULL, FALSE);
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
return TRUE;
}

113
sys/oss/gstosselement.h Normal file
View file

@ -0,0 +1,113 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
*
* gstosselement.h:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_OSS_ELEMENT_H__
#define __GST_OSS_ELEMENT_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_OSSELEMENT \
(gst_osselement_get_type())
#define GST_OSSELEMENT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSSELEMENT,GstOssElement))
#define GST_OSSELEMENT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSSELEMENT,GstOssElementClass))
#define GST_IS_OSSELEMENT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSSELEMENT))
#define GST_IS_OSSELEMENT_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSSELEMENT))
typedef struct _GstOssElement GstOssElement;
typedef struct _GstOssElementClass GstOssElementClass;
typedef enum {
GST_OSSELEMENT_READ,
GST_OSSELEMENT_WRITE,
} GstOssOpenMode;
struct _GstOssElement
{
/* yes, we're a gstelement too */
GstElement parent;
gchar *device,
*mixer_dev;
/* device state */
int fd;
int caps; /* the capabilities */
gint format;
gint fragment;
guint64 fragment_time;
gint fragment_size;
GstOssOpenMode mode;
/* stats */
guint bps;
/* parameters */
gint law;
gint endianness;
gboolean sign;
gint width;
gint depth;
gint channels;
gint rate;
/* mixer stuff */
GList *channellist;
guint32 stereomask,
recdevs,
recmask,
mixcaps;
gint mixer_fd;
};
struct _GstOssElementClass {
GstElementClass klass;
};
GType gst_osselement_get_type (void);
/* factory register function */
gboolean gst_osselement_factory_init (GstPlugin *plugin);
/* some useful functions */
gboolean gst_osselement_parse_caps (GstOssElement *oss,
GstCaps *caps);
gboolean gst_osselement_merge_fixed_caps (GstOssElement *oss,
GstCaps *caps);
gboolean gst_osselement_sync_parms (GstOssElement *oss);
void gst_osselement_reset (GstOssElement *oss);
gboolean gst_osselement_convert (GstOssElement *oss,
GstFormat src_format,
gint64 src_value,
GstFormat *dest_format,
gint64 *dest_value);
G_END_DECLS
#endif /* __GST_OSS_ELEMENT_H__ */

323
sys/oss/gstossmixer.c Normal file
View file

@ -0,0 +1,323 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
*
* gstossmixer.h: mixer interface implementation for OSS
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include "gstossmixer.h"
#define MASK_BIT_IS_SET(mask, bit) \
(mask & (1 << bit))
static gboolean gst_ossmixer_supported (GstInterface *iface);
static const GList * gst_ossmixer_list_channels (GstMixer *ossmixer);
static void gst_ossmixer_set_volume (GstMixer *ossmixer,
GstMixerChannel *channel,
gint *volumes);
static void gst_ossmixer_get_volume (GstMixer *ossmixer,
GstMixerChannel *channel,
gint *volumes);
static void gst_ossmixer_set_record (GstMixer *ossmixer,
GstMixerChannel *channel,
gboolean record);
static void gst_ossmixer_set_mute (GstMixer *ossmixer,
GstMixerChannel *channel,
gboolean mute);
static const gchar *labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
GstMixerChannel *
gst_ossmixer_channel_new (GstOssElement *oss,
gint channel_num,
gint max_chans,
gint flags)
{
GstMixerChannel *channel = (GstMixerChannel *) g_new (GstOssMixerChannel, 1);
gint volumes[2];
channel->label = g_strdup (labels[channel_num]);
channel->num_channels = max_chans;
channel->flags = flags;
channel->min_volume = 0;
channel->max_volume = 100;
((GstOssMixerChannel *) channel)->channel_num = channel_num;
/* volume */
gst_ossmixer_get_volume (GST_MIXER (oss),
channel, volumes);
if (max_chans == 1) {
volumes[1] = 0;
}
((GstOssMixerChannel *) channel)->lvol = volumes[0];
((GstOssMixerChannel *) channel)->rvol = volumes[1];
return channel;
}
void
gst_ossmixer_channel_free (GstMixerChannel *channel)
{
g_free (channel->label);
g_free (channel);
}
void
gst_oss_interface_init (GstInterfaceClass *klass)
{
/* default virtual functions */
klass->supported = gst_ossmixer_supported;
}
void
gst_ossmixer_interface_init (GstMixerClass *klass)
{
/* default virtual functions */
klass->list_channels = gst_ossmixer_list_channels;
klass->set_volume = gst_ossmixer_set_volume;
klass->get_volume = gst_ossmixer_get_volume;
klass->set_mute = gst_ossmixer_set_mute;
klass->set_record = gst_ossmixer_set_record;
}
static gboolean
gst_ossmixer_supported (GstInterface *iface)
{
return (GST_OSSELEMENT (iface)->mixer_fd != -1);
}
static const GList *
gst_ossmixer_list_channels (GstMixer *mixer)
{
GstOssElement *oss = GST_OSSELEMENT (mixer);
g_return_val_if_fail (oss->mixer_fd != -1, NULL);
return (const GList *) GST_OSSELEMENT (mixer)->channellist;
}
static void
gst_ossmixer_get_volume (GstMixer *mixer,
GstMixerChannel *channel,
gint *volumes)
{
gint volume;
GstOssElement *oss = GST_OSSELEMENT (mixer);
GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel;
g_return_if_fail (oss->mixer_fd != -1);
if (channel->flags & GST_MIXER_CHANNEL_MUTE) {
volumes[0] = osschannel->lvol;
if (channel->num_channels == 2) {
volumes[1] = osschannel->rvol;
}
} else {
/* get */
if (ioctl(oss->mixer_fd, MIXER_READ (osschannel->channel_num), &volume) < 0) {
g_warning("Error getting recording device (%d) volume (0x%x): %s\n",
osschannel->channel_num, volume, strerror(errno));
volume = 0;
}
osschannel->lvol = volumes[0] = (volume & 0xff);
if (channel->num_channels == 2) {
osschannel->rvol = volumes[1] = ((volume >> 8) & 0xff);
}
}
}
static void
gst_ossmixer_set_volume (GstMixer *mixer,
GstMixerChannel *channel,
gint *volumes)
{
gint volume;
GstOssElement *oss = GST_OSSELEMENT (mixer);
GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel;
g_return_if_fail (oss->mixer_fd != -1);
/* prepare the value for ioctl() */
if (!(channel->flags & GST_MIXER_CHANNEL_MUTE)) {
volume = (volumes[0] & 0xff);
if (channel->num_channels == 2) {
volume |= ((volumes[1] & 0xff) << 8);
}
/* set */
if (ioctl(oss->mixer_fd, MIXER_WRITE (osschannel->channel_num), &volume) < 0) {
g_warning("Error setting recording device (%d) volume (0x%x): %s\n",
osschannel->channel_num, volume, strerror(errno));
return;
}
}
osschannel->lvol = volumes[0];
if (channel->num_channels == 2) {
osschannel->rvol = volumes[1];
}
}
static void
gst_ossmixer_set_mute (GstMixer *mixer,
GstMixerChannel *channel,
gboolean mute)
{
int volume;
GstOssElement *oss = GST_OSSELEMENT (mixer);
GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel;
g_return_if_fail (oss->mixer_fd != -1);
if (mute) {
volume = 0;
} else {
volume = (osschannel->lvol & 0xff);
if (MASK_BIT_IS_SET (oss->stereomask, osschannel->channel_num)) {
volume |= ((osschannel->rvol & 0xff) << 8);
}
}
if (ioctl(oss->mixer_fd, MIXER_WRITE(osschannel->channel_num), &volume) < 0) {
g_warning("Error setting mixer recording device volume (0x%x): %s",
volume, strerror(errno));
return;
}
if (mute) {
channel->flags |= GST_MIXER_CHANNEL_MUTE;
} else {
channel->flags &= ~GST_MIXER_CHANNEL_MUTE;
}
}
static void
gst_ossmixer_set_record (GstMixer *mixer,
GstMixerChannel *channel,
gboolean record)
{
GstOssElement *oss = GST_OSSELEMENT (mixer);
GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel;
g_return_if_fail (oss->mixer_fd != -1);
/* if we're exclusive, then we need to unset the current one(s) */
if (oss->mixcaps & SOUND_CAP_EXCL_INPUT) {
GList *channel;
for (channel = oss->channellist; channel != NULL; channel = channel->next) {
GstMixerChannel *turn = (GstMixerChannel *) channel->data;
turn->flags &= ~GST_MIXER_CHANNEL_RECORD;
}
oss->recdevs = 0;
}
/* set new record bit, if needed */
if (record) {
oss->recdevs |= (1 << osschannel->channel_num);
} else {
oss->recdevs &= ~(1 << osschannel->channel_num);
}
/* set it to the device */
if (ioctl(oss->mixer_fd, SOUND_MIXER_WRITE_RECSRC, &oss->recdevs) < 0) {
g_warning("Error setting mixer recording devices (0x%x): %s",
oss->recdevs, strerror(errno));
return;
}
if (record) {
channel->flags |= GST_MIXER_CHANNEL_RECORD;
} else {
channel->flags &= ~GST_MIXER_CHANNEL_RECORD;
}
}
void
gst_ossmixer_build_list (GstOssElement *oss)
{
gint i, devmask;
g_return_if_fail (oss->mixer_fd == -1);
oss->mixer_fd = open (oss->mixer_dev, O_RDWR);
if (oss->mixer_fd == -1) {
g_warning ("Failed to open mixer device %s, mixing disabled: %s",
oss->mixer_dev, strerror (errno));
return;
}
/* get masks */
ioctl (oss->mixer_fd, SOUND_MIXER_READ_RECMASK, &oss->recmask);
ioctl (oss->mixer_fd, SOUND_MIXER_READ_RECSRC, &oss->recdevs);
ioctl (oss->mixer_fd, SOUND_MIXER_READ_STEREODEVS, &oss->stereomask);
ioctl (oss->mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask);
ioctl (oss->mixer_fd, SOUND_MIXER_READ_CAPS, &oss->mixcaps);
/* build channel list */
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
if (devmask & (1 << i)) {
GstMixerChannel *channel;
gboolean input = FALSE, stereo = FALSE, record = FALSE;
/* channel exists, make up capabilities */
if (MASK_BIT_IS_SET (oss->stereomask, i))
stereo = TRUE;
if (MASK_BIT_IS_SET (oss->recmask, i))
input = TRUE;
if (MASK_BIT_IS_SET (oss->recdevs, i))
record = TRUE;
/* add channel to list */
channel = gst_ossmixer_channel_new (oss, i, stereo ? 2 : 1,
(record ? GST_MIXER_CHANNEL_RECORD : 0) |
(input ? GST_MIXER_CHANNEL_INPUT :
GST_MIXER_CHANNEL_OUTPUT));
oss->channellist = g_list_append (oss->channellist, channel);
}
}
}
void
gst_ossmixer_free_list (GstOssElement *oss)
{
g_return_if_fail (oss->mixer_fd != -1);
g_list_foreach (oss->channellist, (GFunc) gst_ossmixer_channel_free, NULL);
g_list_free (oss->channellist);
oss->channellist = NULL;
close (oss->mixer_fd);
oss->mixer_fd = -1;
}

45
sys/oss/gstossmixer.h Normal file
View file

@ -0,0 +1,45 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
*
* gstossmixer.h: mixer interface implementation for OSS
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_OSS_MIXER_H__
#define __GST_OSS_MIXER_H__
#include <gst/gst.h>
#include <gst/mixer/mixer.h>
#include "gstosselement.h"
G_BEGIN_DECLS
typedef struct _GstOssMixerChannel {
GstMixerChannel parent;
gint lvol, rvol;
gint channel_num;
} GstOssMixerChannel;
void gst_ossmixer_interface_init (GstMixerClass *klass);
void gst_oss_interface_init (GstInterfaceClass *klass);
void gst_ossmixer_build_list (GstOssElement *oss);
void gst_ossmixer_free_list (GstOssElement *oss);
G_END_DECLS
#endif /* __GST_OSS_MIXER_H__ */

View file

@ -45,7 +45,6 @@ static GstElementDetails gst_osssink_details = {
static void gst_osssink_class_init (GstOssSinkClass *klass); static void gst_osssink_class_init (GstOssSinkClass *klass);
static void gst_osssink_init (GstOssSink *osssink); static void gst_osssink_init (GstOssSink *osssink);
static void gst_osssink_dispose (GObject *object); static void gst_osssink_dispose (GObject *object);
static void gst_osssink_finalize (GObject *object);
static GstElementStateReturn gst_osssink_change_state (GstElement *element); static GstElementStateReturn gst_osssink_change_state (GstElement *element);
static void gst_osssink_set_clock (GstElement *element, GstClock *clock); static void gst_osssink_set_clock (GstElement *element, GstClock *clock);
@ -78,7 +77,6 @@ enum {
enum { enum {
ARG_0, ARG_0,
ARG_DEVICE,
ARG_MUTE, ARG_MUTE,
ARG_FRAGMENT, ARG_FRAGMENT,
ARG_BUFFER_SIZE, ARG_BUFFER_SIZE,
@ -132,7 +130,7 @@ gst_osssink_get_type (void)
0, 0,
(GInstanceInitFunc)gst_osssink_init, (GInstanceInitFunc)gst_osssink_init,
}; };
osssink_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOssSink", &osssink_info, 0); osssink_type = g_type_register_static (GST_TYPE_OSSELEMENT, "GstOssSink", &osssink_info, 0);
} }
return osssink_type; return osssink_type;
@ -162,16 +160,6 @@ gst_osssink_dispose (GObject *object)
G_OBJECT_CLASS (parent_class)->dispose (object); G_OBJECT_CLASS (parent_class)->dispose (object);
} }
static void
gst_osssink_finalize (GObject *object)
{
GstOssSink *osssink = (GstOssSink *) object;
g_free (osssink->common.device);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void static void
gst_osssink_class_init (GstOssSinkClass *klass) gst_osssink_class_init (GstOssSinkClass *klass)
{ {
@ -181,11 +169,8 @@ gst_osssink_class_init (GstOssSinkClass *klass)
gobject_class = (GObjectClass*)klass; gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass; gstelement_class = (GstElementClass*)klass;
parent_class = g_type_class_ref(GST_TYPE_ELEMENT); parent_class = g_type_class_ref(GST_TYPE_OSSELEMENT);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE,
g_param_spec_string ("device", "Device", "The device to use for output",
"/dev/dsp", G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MUTE, g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MUTE,
g_param_spec_boolean ("mute", "Mute", "Mute the audio", g_param_spec_boolean ("mute", "Mute", "Mute the audio",
FALSE, G_PARAM_READWRITE)); FALSE, G_PARAM_READWRITE));
@ -211,7 +196,6 @@ gst_osssink_class_init (GstOssSinkClass *klass)
gobject_class->set_property = gst_osssink_set_property; gobject_class->set_property = gst_osssink_set_property;
gobject_class->get_property = gst_osssink_get_property; gobject_class->get_property = gst_osssink_get_property;
gobject_class->dispose = gst_osssink_dispose; gobject_class->dispose = gst_osssink_dispose;
gobject_class->finalize = gst_osssink_finalize;
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_osssink_change_state); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_osssink_change_state);
gstelement_class->query = GST_DEBUG_FUNCPTR (gst_osssink_query); gstelement_class->query = GST_DEBUG_FUNCPTR (gst_osssink_query);
@ -235,8 +219,6 @@ gst_osssink_init (GstOssSink *osssink)
gst_pad_set_chain_function (osssink->sinkpad, gst_osssink_chain); gst_pad_set_chain_function (osssink->sinkpad, gst_osssink_chain);
gst_osscommon_init (&osssink->common);
osssink->bufsize = 4096; osssink->bufsize = 4096;
osssink->chunk_size = 4096; osssink->chunk_size = 4096;
osssink->resync = FALSE; osssink->resync = FALSE;
@ -260,10 +242,10 @@ gst_osssink_sinkconnect (GstPad *pad, GstCaps *caps)
if (!GST_CAPS_IS_FIXED (caps)) if (!GST_CAPS_IS_FIXED (caps))
return GST_PAD_LINK_DELAYED; return GST_PAD_LINK_DELAYED;
if (!gst_osscommon_parse_caps (&osssink->common, caps)) if (!gst_osselement_parse_caps (GST_OSSELEMENT (osssink), caps))
return GST_PAD_LINK_REFUSED; return GST_PAD_LINK_REFUSED;
if (!gst_osscommon_sync_parms (&osssink->common)) { if (!gst_osselement_sync_parms (GST_OSSELEMENT (osssink))) {
return GST_PAD_LINK_REFUSED; return GST_PAD_LINK_REFUSED;
} }
@ -275,12 +257,12 @@ gst_osssink_get_delay (GstOssSink *osssink)
{ {
gint delay = 0; gint delay = 0;
if (osssink->common.fd == -1) if (GST_OSSELEMENT (osssink)->fd == -1)
return 0; return 0;
if (ioctl (osssink->common.fd, SNDCTL_DSP_GETODELAY, &delay) < 0) { if (ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_GETODELAY, &delay) < 0) {
audio_buf_info info; audio_buf_info info;
if (ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { if (ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
delay = 0; delay = 0;
} }
else { else {
@ -297,7 +279,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data)
gint delay; gint delay;
GstClockTime res; GstClockTime res;
if (!osssink->common.bps) if (!GST_OSSELEMENT (osssink)->bps)
return 0; return 0;
delay = gst_osssink_get_delay (osssink); delay = gst_osssink_get_delay (osssink);
@ -308,7 +290,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data)
if (((guint64)delay) > osssink->handled) { if (((guint64)delay) > osssink->handled) {
delay = osssink->handled; delay = osssink->handled;
} }
res = (osssink->handled - delay) * GST_SECOND / osssink->common.bps; res = (osssink->handled - delay) * GST_SECOND / GST_OSSELEMENT (osssink)->bps;
return res; return res;
} }
@ -347,7 +329,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_EOS: case GST_EVENT_EOS:
ioctl (osssink->common.fd, SNDCTL_DSP_SYNC); ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_SYNC);
gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE); gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE);
gst_pad_event_default (pad, event); gst_pad_event_default (pad, event);
return; return;
@ -355,7 +337,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
{ {
gint64 value; gint64 value;
ioctl (osssink->common.fd, SNDCTL_DSP_RESET); ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_RESET);
if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) { if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) {
if (!gst_clock_handle_discont (osssink->clock, value)) if (!gst_clock_handle_discont (osssink->clock, value))
gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE); gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE);
@ -372,7 +354,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
return; return;
} }
if (!osssink->common.bps) { if (!GST_OSSELEMENT (osssink)->bps) {
gst_buffer_unref (buf); gst_buffer_unref (buf);
gst_element_error (GST_ELEMENT (osssink), "capsnego was never performed, unknown data type"); gst_element_error (GST_ELEMENT (osssink), "capsnego was never performed, unknown data type");
return; return;
@ -380,7 +362,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
buftime = GST_BUFFER_TIMESTAMP (buf); buftime = GST_BUFFER_TIMESTAMP (buf);
if (osssink->common.fd >= 0) { if (GST_OSSELEMENT (osssink)->fd >= 0) {
if (!osssink->mute) { if (!osssink->mute) {
guchar *data = GST_BUFFER_DATA (buf); guchar *data = GST_BUFFER_DATA (buf);
gint size = GST_BUFFER_SIZE (buf); gint size = GST_BUFFER_SIZE (buf);
@ -392,7 +374,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
GstClockTimeDiff jitter; GstClockTimeDiff jitter;
delay = gst_osssink_get_delay (osssink); delay = gst_osssink_get_delay (osssink);
queued = delay * GST_SECOND / osssink->common.bps; queued = delay * GST_SECOND / GST_OSSELEMENT (osssink)->bps;
if (osssink->resync && osssink->sync) { if (osssink->resync && osssink->sync) {
GstClockID id = gst_clock_new_single_shot_id (osssink->clock, buftime - queued); GstClockID id = gst_clock_new_single_shot_id (osssink->clock, buftime - queued);
@ -415,7 +397,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
else { else {
audio_buf_info ospace; audio_buf_info ospace;
ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &ospace); ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_GETOSPACE, &ospace);
if (ospace.bytes >= size) { if (ospace.bytes >= size) {
to_write = size; to_write = size;
@ -423,7 +405,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
} }
while (to_write > 0) { while (to_write > 0) {
gint done = write (osssink->common.fd, data, gint done = write (GST_OSSELEMENT (osssink)->fd, data,
MIN (to_write, osssink->chunk_size)); MIN (to_write, osssink->chunk_size));
if (done == -1) { if (done == -1) {
@ -464,7 +446,8 @@ gst_osssink_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
osssink = GST_OSSSINK (gst_pad_get_parent (pad)); osssink = GST_OSSSINK (gst_pad_get_parent (pad));
return gst_osscommon_convert (&osssink->common, src_format, src_value, return gst_osselement_convert (GST_OSSELEMENT (osssink),
src_format, src_value,
dest_format, dest_value); dest_format, dest_value);
} }
@ -528,23 +511,13 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G
osssink = GST_OSSSINK (object); osssink = GST_OSSSINK (object);
switch (prop_id) { switch (prop_id) {
case ARG_DEVICE:
/* disallow changing the device while it is opened
get_property("device") should return the right one */
if (!GST_FLAG_IS_SET (osssink, GST_OSSSINK_OPEN))
{
g_free (osssink->common.device);
osssink->common.device = g_strdup (g_value_get_string (value));
g_object_notify (object, "device");
}
break;
case ARG_MUTE: case ARG_MUTE:
osssink->mute = g_value_get_boolean (value); osssink->mute = g_value_get_boolean (value);
g_object_notify (G_OBJECT (osssink), "mute"); g_object_notify (G_OBJECT (osssink), "mute");
break; break;
case ARG_FRAGMENT: case ARG_FRAGMENT:
osssink->common.fragment = g_value_get_int (value); GST_OSSELEMENT (osssink)->fragment = g_value_get_int (value);
gst_osscommon_sync_parms (&osssink->common); gst_osselement_sync_parms (GST_OSSELEMENT (osssink));
break; break;
case ARG_BUFFER_SIZE: case ARG_BUFFER_SIZE:
osssink->bufsize = g_value_get_uint (value); osssink->bufsize = g_value_get_uint (value);
@ -572,14 +545,11 @@ gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamS
osssink = GST_OSSSINK (object); osssink = GST_OSSSINK (object);
switch (prop_id) { switch (prop_id) {
case ARG_DEVICE:
g_value_set_string (value, osssink->common.device);
break;
case ARG_MUTE: case ARG_MUTE:
g_value_set_boolean (value, osssink->mute); g_value_set_boolean (value, osssink->mute);
break; break;
case ARG_FRAGMENT: case ARG_FRAGMENT:
g_value_set_int (value, osssink->common.fragment); g_value_set_int (value, GST_OSSELEMENT (osssink)->fragment);
break; break;
case ARG_BUFFER_SIZE: case ARG_BUFFER_SIZE:
g_value_set_uint (value, osssink->bufsize); g_value_set_uint (value, osssink->bufsize);
@ -604,43 +574,23 @@ gst_osssink_change_state (GstElement *element)
osssink = GST_OSSSINK (element); osssink = GST_OSSSINK (element);
switch (GST_STATE_TRANSITION (element)) { switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
if (!GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) {
gchar *error;
if (!gst_osscommon_open_audio (&osssink->common, GST_OSSCOMMON_WRITE, &error)) {
gst_element_error (GST_ELEMENT (osssink), error);
g_free (error);
return GST_STATE_FAILURE;
}
GST_FLAG_SET (element, GST_OSSSINK_OPEN);
}
break;
case GST_STATE_READY_TO_PAUSED: case GST_STATE_READY_TO_PAUSED:
break; break;
case GST_STATE_PAUSED_TO_PLAYING: case GST_STATE_PAUSED_TO_PLAYING:
osssink->resync = TRUE; osssink->resync = TRUE;
break; break;
case GST_STATE_PLAYING_TO_PAUSED: case GST_STATE_PLAYING_TO_PAUSED:
{
if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN))
ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0); ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_RESET, 0);
gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE); gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE);
osssink->resync = TRUE; osssink->resync = TRUE;
break; break;
}
case GST_STATE_PAUSED_TO_READY: case GST_STATE_PAUSED_TO_READY:
if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN))
ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0); ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_RESET, 0);
gst_osscommon_reset (&osssink->common); gst_osselement_reset (GST_OSSELEMENT (osssink));
break; break;
case GST_STATE_READY_TO_NULL: default:
if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) {
gst_osscommon_close_audio (&osssink->common);
GST_FLAG_UNSET (osssink, GST_OSSSINK_OPEN);
GST_INFO ( "osssink: closed sound device");
}
break; break;
} }

View file

@ -27,7 +27,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include "gstosscommon.h" #include "gstosselement.h"
#include <gst/audio/audioclock.h> #include <gst/audio/audioclock.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -53,7 +53,7 @@ typedef struct _GstOssSink GstOssSink;
typedef struct _GstOssSinkClass GstOssSinkClass; typedef struct _GstOssSinkClass GstOssSinkClass;
struct _GstOssSink { struct _GstOssSink {
GstElement element; GstOssElement element;
GstPad *sinkpad; GstPad *sinkpad;
GstBufferPool *sinkpool; GstBufferPool *sinkpool;
@ -64,12 +64,9 @@ struct _GstOssSink {
gboolean sync; gboolean sync;
guint64 handled; guint64 handled;
GstOssCommon common;
gboolean mute; gboolean mute;
guint bufsize; guint bufsize;
guint chunk_size; guint chunk_size;
}; };
struct _GstOssSinkClass { struct _GstOssSinkClass {

View file

@ -33,7 +33,7 @@
#include <string.h> #include <string.h>
#include <gstosssrc.h> #include <gstosssrc.h>
#include <gstosscommon.h> #include <gstosselement.h>
#include <gst/audio/audioclock.h> #include <gst/audio/audioclock.h>
/* elementfactory information */ /* elementfactory information */
@ -56,7 +56,6 @@ enum {
enum { enum {
ARG_0, ARG_0,
ARG_DEVICE,
ARG_BUFFERSIZE, ARG_BUFFERSIZE,
ARG_FRAGMENT, ARG_FRAGMENT,
}; };
@ -89,7 +88,6 @@ GST_PAD_TEMPLATE_FACTORY (osssrc_src_factory,
static void gst_osssrc_class_init (GstOssSrcClass *klass); static void gst_osssrc_class_init (GstOssSrcClass *klass);
static void gst_osssrc_init (GstOssSrc *osssrc); static void gst_osssrc_init (GstOssSrc *osssrc);
static void gst_osssrc_dispose (GObject *object); static void gst_osssrc_dispose (GObject *object);
static void gst_osssrc_finalize (GObject *object);
static GstPadLinkReturn gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps); static GstPadLinkReturn gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps);
static const GstFormat* gst_osssrc_get_formats (GstPad *pad); static const GstFormat* gst_osssrc_get_formats (GstPad *pad);
@ -136,7 +134,7 @@ gst_osssrc_get_type (void)
0, 0,
(GInstanceInitFunc)gst_osssrc_init, (GInstanceInitFunc)gst_osssrc_init,
}; };
osssrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOssSrc", &osssrc_info, 0); osssrc_type = g_type_register_static (GST_TYPE_OSSELEMENT, "GstOssSrc", &osssrc_info, 0);
} }
return osssrc_type; return osssrc_type;
} }
@ -150,14 +148,11 @@ gst_osssrc_class_init (GstOssSrcClass *klass)
gobject_class = (GObjectClass*)klass; gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass; gstelement_class = (GstElementClass*)klass;
parent_class = g_type_class_ref (GST_TYPE_ELEMENT); parent_class = g_type_class_ref (GST_TYPE_OSSELEMENT);
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFFERSIZE, g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFFERSIZE,
g_param_spec_ulong ("buffersize","Buffer Size","The size of the buffers with samples", g_param_spec_ulong ("buffersize","Buffer Size","The size of the buffers with samples",
0, G_MAXULONG, 0, G_PARAM_READWRITE)); 0, G_MAXULONG, 0, G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
g_param_spec_string ("device", "device", "oss device (/dev/dspN usually)",
"default", G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FRAGMENT, g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FRAGMENT,
g_param_spec_int ("fragment", "Fragment", g_param_spec_int ("fragment", "Fragment",
"The fragment as 0xMMMMSSSS (MMMM = total fragments, 2^SSSS = fragment size)", "The fragment as 0xMMMMSSSS (MMMM = total fragments, 2^SSSS = fragment size)",
@ -166,7 +161,6 @@ gst_osssrc_class_init (GstOssSrcClass *klass)
gobject_class->set_property = gst_osssrc_set_property; gobject_class->set_property = gst_osssrc_set_property;
gobject_class->get_property = gst_osssrc_get_property; gobject_class->get_property = gst_osssrc_get_property;
gobject_class->dispose = gst_osssrc_dispose; gobject_class->dispose = gst_osssrc_dispose;
gobject_class->finalize = gst_osssrc_finalize;
gstelement_class->change_state = gst_osssrc_change_state; gstelement_class->change_state = gst_osssrc_change_state;
gstelement_class->send_event = gst_osssrc_send_event; gstelement_class->send_event = gst_osssrc_send_event;
@ -192,8 +186,6 @@ gst_osssrc_init (GstOssSrc *osssrc)
gst_element_add_pad (GST_ELEMENT (osssrc), osssrc->srcpad); gst_element_add_pad (GST_ELEMENT (osssrc), osssrc->srcpad);
gst_osscommon_init (&osssrc->common);
osssrc->buffersize = 4096; osssrc->buffersize = 4096;
osssrc->curoffset = 0; osssrc->curoffset = 0;
@ -202,6 +194,7 @@ gst_osssrc_init (GstOssSrc *osssrc)
osssrc->clock = NULL; osssrc->clock = NULL;
} }
static void static void
gst_osssrc_dispose (GObject *object) gst_osssrc_dispose (GObject *object)
{ {
@ -211,16 +204,6 @@ gst_osssrc_dispose (GObject *object)
G_OBJECT_CLASS (parent_class)->dispose (object); G_OBJECT_CLASS (parent_class)->dispose (object);
} }
static void
gst_osssrc_finalize (GObject *object)
{
GstOssSrc *osssrc = (GstOssSrc *) object;
g_free (osssrc->common.device);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static GstPadLinkReturn static GstPadLinkReturn
gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps) gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps)
@ -232,10 +215,10 @@ gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps)
if (!GST_CAPS_IS_FIXED (caps)) if (!GST_CAPS_IS_FIXED (caps))
return GST_PAD_LINK_DELAYED; return GST_PAD_LINK_DELAYED;
if (!gst_osscommon_parse_caps (&src->common, caps)) if (!gst_osselement_parse_caps (GST_OSSELEMENT (src), caps))
return GST_PAD_LINK_REFUSED; return GST_PAD_LINK_REFUSED;
if (!gst_osscommon_sync_parms (&src->common)) if (!gst_osselement_sync_parms (GST_OSSELEMENT (src)))
return GST_PAD_LINK_REFUSED; return GST_PAD_LINK_REFUSED;
return GST_PAD_LINK_OK; return GST_PAD_LINK_OK;
@ -251,10 +234,10 @@ gst_osssrc_negotiate (GstPad *pad)
allowed = gst_pad_get_allowed_caps (pad); allowed = gst_pad_get_allowed_caps (pad);
if (!gst_osscommon_merge_fixed_caps (&src->common, allowed)) if (!gst_osselement_merge_fixed_caps (GST_OSSELEMENT (src), allowed))
return FALSE; return FALSE;
if (!gst_osscommon_sync_parms (&src->common)) if (!gst_osselement_sync_parms (GST_OSSELEMENT (src)))
return FALSE; return FALSE;
/* set caps on src pad */ /* set caps on src pad */
@ -262,12 +245,12 @@ gst_osssrc_negotiate (GstPad *pad)
GST_CAPS_NEW ( GST_CAPS_NEW (
"oss_src", "oss_src",
"audio/x-raw-int", "audio/x-raw-int",
"endianness", GST_PROPS_INT (src->common.endianness), "endianness", GST_PROPS_INT (GST_OSSELEMENT (src)->endianness),
"signed", GST_PROPS_BOOLEAN (src->common.sign), "signed", GST_PROPS_BOOLEAN (GST_OSSELEMENT (src)->sign),
"width", GST_PROPS_INT (src->common.width), "width", GST_PROPS_INT (GST_OSSELEMENT (src)->width),
"depth", GST_PROPS_INT (src->common.depth), "depth", GST_PROPS_INT (GST_OSSELEMENT (src)->depth),
"rate", GST_PROPS_INT (src->common.rate), "rate", GST_PROPS_INT (GST_OSSELEMENT (src)->rate),
"channels", GST_PROPS_INT (src->common.channels) "channels", GST_PROPS_INT (GST_OSSELEMENT (src)->channels)
)) <= 0) )) <= 0)
{ {
return FALSE; return FALSE;
@ -281,13 +264,13 @@ gst_osssrc_get_time (GstClock *clock, gpointer data)
GstOssSrc *osssrc = GST_OSSSRC (data); GstOssSrc *osssrc = GST_OSSSRC (data);
audio_buf_info info; audio_buf_info info;
if (!osssrc->common.bps) if (!GST_OSSELEMENT (osssrc)->bps)
return 0; return 0;
if (ioctl(osssrc->common.fd, SNDCTL_DSP_GETISPACE, &info) < 0) if (ioctl(GST_OSSELEMENT (osssrc)->fd, SNDCTL_DSP_GETISPACE, &info) < 0)
return 0; return 0;
return (osssrc->curoffset + info.bytes) * GST_SECOND / osssrc->common.bps; return (osssrc->curoffset + info.bytes) * GST_SECOND / GST_OSSELEMENT (osssrc)->bps;
} }
static GstClock* static GstClock*
@ -336,13 +319,13 @@ gst_osssrc_get (GstPad *pad)
return GST_BUFFER (gst_event_new (GST_EVENT_INTERRUPT)); return GST_BUFFER (gst_event_new (GST_EVENT_INTERRUPT));
} }
} }
if (src->common.bps == 0) { if (GST_OSSELEMENT (src)->bps == 0) {
gst_buffer_unref (buf); gst_buffer_unref (buf);
gst_element_error (GST_ELEMENT (src), "no format negotiated"); gst_element_error (GST_ELEMENT (src), "no format negotiated");
return GST_BUFFER (gst_event_new (GST_EVENT_INTERRUPT)); return GST_BUFFER (gst_event_new (GST_EVENT_INTERRUPT));
} }
readbytes = read (src->common.fd,GST_BUFFER_DATA (buf), readbytes = read (GST_OSSELEMENT (src)->fd,GST_BUFFER_DATA (buf),
src->buffersize); src->buffersize);
if (readbytes < 0) { if (readbytes < 0) {
gst_buffer_unref (buf); gst_buffer_unref (buf);
@ -361,7 +344,9 @@ gst_osssrc_get (GstPad *pad)
GST_BUFFER_OFFSET (buf) = src->curoffset; GST_BUFFER_OFFSET (buf) = src->curoffset;
/* FIXME: we are falsely assuming that we are the master clock here */ /* FIXME: we are falsely assuming that we are the master clock here */
GST_BUFFER_TIMESTAMP (buf) = src->curoffset * GST_SECOND / src->common.bps; GST_BUFFER_TIMESTAMP (buf) = src->curoffset * GST_SECOND / GST_OSSELEMENT (src)->bps;
GST_BUFFER_DURATION (buf) = (GST_SECOND * GST_BUFFER_SIZE (buf)) /
(GST_OSSELEMENT (src)->bps * GST_OSSELEMENT (src)->rate);
src->curoffset += readbytes; src->curoffset += readbytes;
@ -382,13 +367,9 @@ gst_osssrc_set_property (GObject *object, guint prop_id, const GValue *value, GP
case ARG_BUFFERSIZE: case ARG_BUFFERSIZE:
src->buffersize = g_value_get_ulong (value); src->buffersize = g_value_get_ulong (value);
break; break;
case ARG_DEVICE:
g_free(src->common.device);
src->common.device = g_strdup (g_value_get_string (value));
break;
case ARG_FRAGMENT: case ARG_FRAGMENT:
src->common.fragment = g_value_get_int (value); GST_OSSELEMENT (src)->fragment = g_value_get_int (value);
gst_osscommon_sync_parms (&src->common); gst_osselement_sync_parms (GST_OSSELEMENT (src));
break; break;
default: default:
break; break;
@ -406,11 +387,8 @@ gst_osssrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSp
case ARG_BUFFERSIZE: case ARG_BUFFERSIZE:
g_value_set_ulong (value, src->buffersize); g_value_set_ulong (value, src->buffersize);
break; break;
case ARG_DEVICE:
g_value_set_string (value, src->common.device);
break;
case ARG_FRAGMENT: case ARG_FRAGMENT:
g_value_set_int (value, src->common.fragment); g_value_set_int (value, GST_OSSELEMENT (src)->fragment);
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -426,17 +404,6 @@ gst_osssrc_change_state (GstElement *element)
GST_DEBUG ("osssrc: state change"); GST_DEBUG ("osssrc: state change");
switch (GST_STATE_TRANSITION (element)) { switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
if (!GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) {
gchar *error;
if (!gst_osscommon_open_audio (&osssrc->common, GST_OSSCOMMON_READ, &error)) {
gst_element_error (GST_ELEMENT (osssrc), error);
g_free (error);
return GST_STATE_FAILURE;
}
GST_FLAG_SET (osssrc, GST_OSSSRC_OPEN);
}
break;
case GST_STATE_READY_TO_PAUSED: case GST_STATE_READY_TO_PAUSED:
osssrc->curoffset = 0; osssrc->curoffset = 0;
break; break;
@ -448,14 +415,9 @@ gst_osssrc_change_state (GstElement *element)
break; break;
case GST_STATE_PAUSED_TO_READY: case GST_STATE_PAUSED_TO_READY:
if (GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) if (GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN))
ioctl (osssrc->common.fd, SNDCTL_DSP_RESET, 0); ioctl (GST_OSSELEMENT (osssrc)->fd, SNDCTL_DSP_RESET, 0);
break; break;
case GST_STATE_READY_TO_NULL: default:
if (GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) {
gst_osscommon_close_audio (&osssrc->common);
GST_FLAG_UNSET (osssrc, GST_OSSSRC_OPEN);
}
gst_osscommon_init (&osssrc->common);
break; break;
} }
@ -485,7 +447,7 @@ gst_osssrc_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
osssrc = GST_OSSSRC (gst_pad_get_parent (pad)); osssrc = GST_OSSSRC (gst_pad_get_parent (pad));
return gst_osscommon_convert (&osssrc->common, src_format, src_value, return gst_osselement_convert (GST_OSSELEMENT (osssrc), src_format, src_value,
dest_format, dest_value); dest_format, dest_value);
} }
@ -521,7 +483,7 @@ gst_osssrc_src_event (GstPad *pad, GstEvent *event)
format = GST_FORMAT_BYTES; format = GST_FORMAT_BYTES;
/* convert to bytes */ /* convert to bytes */
if (gst_osscommon_convert (&osssrc->common, if (gst_osselement_convert (GST_OSSELEMENT (osssrc),
GST_EVENT_SIZE_FORMAT (event), GST_EVENT_SIZE_FORMAT (event),
GST_EVENT_SIZE_VALUE (event), GST_EVENT_SIZE_VALUE (event),
&format, &value)) &format, &value))
@ -567,7 +529,7 @@ gst_osssrc_src_query (GstPad *pad, GstQueryType type, GstFormat *format, gint64
switch (type) { switch (type) {
case GST_QUERY_POSITION: case GST_QUERY_POSITION:
res = gst_osscommon_convert (&osssrc->common, res = gst_osselement_convert (GST_OSSELEMENT (osssrc),
GST_FORMAT_BYTES, osssrc->curoffset, GST_FORMAT_BYTES, osssrc->curoffset,
format, value); format, value);
break; break;

View file

@ -26,7 +26,7 @@
#include <gst/gst.h> #include <gst/gst.h>
#include "gstosscommon.h" #include "gstosselement.h"
G_BEGIN_DECLS G_BEGIN_DECLS
@ -51,13 +51,11 @@ typedef struct _GstOssSrc GstOssSrc;
typedef struct _GstOssSrcClass GstOssSrcClass; typedef struct _GstOssSrcClass GstOssSrcClass;
struct _GstOssSrc { struct _GstOssSrc {
GstElement element; GstOssElement element;
/* pads */ /* pads */
GstPad *srcpad; GstPad *srcpad;
GstOssCommon common;
gboolean need_eos; /* Do we need to emit an EOS? */ gboolean need_eos; /* Do we need to emit an EOS? */
/* blocking */ /* blocking */