mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
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:
parent
adda650f23
commit
96fc83aeac
10 changed files with 1249 additions and 173 deletions
|
@ -3,11 +3,12 @@ plugin_LTLIBRARIES = libgstossaudio.la
|
|||
|
||||
EXTRA_LTLIBRARIES = libgstosshelper.la
|
||||
|
||||
libgstossaudio_la_SOURCES = gstosssink.c \
|
||||
libgstossaudio_la_SOURCES = gstossaudio.c \
|
||||
gstosselement.c \
|
||||
gstossmixer.c \
|
||||
gstosssink.c \
|
||||
gstosssrc.c \
|
||||
gstossaudio.c \
|
||||
gstossgst.c \
|
||||
gstosscommon.c
|
||||
gstossgst.c
|
||||
|
||||
libgstossaudio_la_CFLAGS = $(GST_CFLAGS)
|
||||
libgstossaudio_la_LIBADD =
|
||||
|
@ -16,4 +17,9 @@ libgstossaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
|||
libgstosshelper_la_SOURCES = gstosshelper.c
|
||||
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
|
||||
|
|
|
@ -17,7 +17,11 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "gstosselement.h"
|
||||
#include "gstosssink.h"
|
||||
#include "gstosssrc.h"
|
||||
#include "gstossgst.h"
|
||||
|
@ -25,19 +29,16 @@
|
|||
static gboolean
|
||||
plugin_init (GModule *module, GstPlugin *plugin)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
if (!gst_library_load ("gstaudio"))
|
||||
return FALSE;
|
||||
|
||||
ret = gst_osssink_factory_init (plugin);
|
||||
g_return_val_if_fail (ret == TRUE, FALSE);
|
||||
|
||||
ret = gst_osssrc_factory_init (plugin);
|
||||
g_return_val_if_fail (ret == TRUE, FALSE);
|
||||
|
||||
ret = gst_ossgst_factory_init (plugin);
|
||||
g_return_val_if_fail (ret == TRUE, FALSE);
|
||||
if (!gst_osselement_factory_init (plugin) ||
|
||||
!gst_osssrc_factory_init (plugin) ||
|
||||
!gst_osssink_factory_init (plugin) ||
|
||||
!gst_ossgst_factory_init (plugin)) {
|
||||
g_warning ("Failed to register OSS elements!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
681
sys/oss/gstosselement.c
Normal file
681
sys/oss/gstosselement.c
Normal 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
113
sys/oss/gstosselement.h
Normal 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
323
sys/oss/gstossmixer.c
Normal 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
45
sys/oss/gstossmixer.h
Normal 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__ */
|
|
@ -45,7 +45,6 @@ static GstElementDetails gst_osssink_details = {
|
|||
static void gst_osssink_class_init (GstOssSinkClass *klass);
|
||||
static void gst_osssink_init (GstOssSink *osssink);
|
||||
static void gst_osssink_dispose (GObject *object);
|
||||
static void gst_osssink_finalize (GObject *object);
|
||||
|
||||
static GstElementStateReturn gst_osssink_change_state (GstElement *element);
|
||||
static void gst_osssink_set_clock (GstElement *element, GstClock *clock);
|
||||
|
@ -78,7 +77,6 @@ enum {
|
|||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_DEVICE,
|
||||
ARG_MUTE,
|
||||
ARG_FRAGMENT,
|
||||
ARG_BUFFER_SIZE,
|
||||
|
@ -132,7 +130,7 @@ gst_osssink_get_type (void)
|
|||
0,
|
||||
(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;
|
||||
|
@ -162,16 +160,6 @@ gst_osssink_dispose (GObject *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
|
||||
gst_osssink_class_init (GstOssSinkClass *klass)
|
||||
{
|
||||
|
@ -181,11 +169,8 @@ gst_osssink_class_init (GstOssSinkClass *klass)
|
|||
gobject_class = (GObjectClass*)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_param_spec_boolean ("mute", "Mute", "Mute the audio",
|
||||
FALSE, G_PARAM_READWRITE));
|
||||
|
@ -211,7 +196,6 @@ gst_osssink_class_init (GstOssSinkClass *klass)
|
|||
gobject_class->set_property = gst_osssink_set_property;
|
||||
gobject_class->get_property = gst_osssink_get_property;
|
||||
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->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_osscommon_init (&osssink->common);
|
||||
|
||||
osssink->bufsize = 4096;
|
||||
osssink->chunk_size = 4096;
|
||||
osssink->resync = FALSE;
|
||||
|
@ -260,10 +242,10 @@ gst_osssink_sinkconnect (GstPad *pad, GstCaps *caps)
|
|||
if (!GST_CAPS_IS_FIXED (caps))
|
||||
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;
|
||||
|
||||
if (!gst_osscommon_sync_parms (&osssink->common)) {
|
||||
if (!gst_osselement_sync_parms (GST_OSSELEMENT (osssink))) {
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
}
|
||||
|
||||
|
@ -275,12 +257,12 @@ gst_osssink_get_delay (GstOssSink *osssink)
|
|||
{
|
||||
gint delay = 0;
|
||||
|
||||
if (osssink->common.fd == -1)
|
||||
if (GST_OSSELEMENT (osssink)->fd == -1)
|
||||
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;
|
||||
if (ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
|
||||
if (ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
|
||||
delay = 0;
|
||||
}
|
||||
else {
|
||||
|
@ -297,7 +279,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data)
|
|||
gint delay;
|
||||
GstClockTime res;
|
||||
|
||||
if (!osssink->common.bps)
|
||||
if (!GST_OSSELEMENT (osssink)->bps)
|
||||
return 0;
|
||||
|
||||
delay = gst_osssink_get_delay (osssink);
|
||||
|
@ -308,7 +290,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data)
|
|||
if (((guint64)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;
|
||||
}
|
||||
|
@ -347,7 +329,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
|||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
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_pad_event_default (pad, event);
|
||||
return;
|
||||
|
@ -355,7 +337,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
|||
{
|
||||
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_clock_handle_discont (osssink->clock, value))
|
||||
gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE);
|
||||
|
@ -372,7 +354,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!osssink->common.bps) {
|
||||
if (!GST_OSSELEMENT (osssink)->bps) {
|
||||
gst_buffer_unref (buf);
|
||||
gst_element_error (GST_ELEMENT (osssink), "capsnego was never performed, unknown data type");
|
||||
return;
|
||||
|
@ -380,7 +362,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
|||
|
||||
buftime = GST_BUFFER_TIMESTAMP (buf);
|
||||
|
||||
if (osssink->common.fd >= 0) {
|
||||
if (GST_OSSELEMENT (osssink)->fd >= 0) {
|
||||
if (!osssink->mute) {
|
||||
guchar *data = GST_BUFFER_DATA (buf);
|
||||
gint size = GST_BUFFER_SIZE (buf);
|
||||
|
@ -392,7 +374,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
|||
GstClockTimeDiff jitter;
|
||||
|
||||
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) {
|
||||
GstClockID id = gst_clock_new_single_shot_id (osssink->clock, buftime - queued);
|
||||
|
@ -415,7 +397,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
|||
else {
|
||||
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) {
|
||||
to_write = size;
|
||||
|
@ -423,7 +405,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
|||
}
|
||||
|
||||
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));
|
||||
|
||||
if (done == -1) {
|
||||
|
@ -464,8 +446,9 @@ gst_osssink_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
|
||||
osssink = GST_OSSSINK (gst_pad_get_parent (pad));
|
||||
|
||||
return gst_osscommon_convert (&osssink->common, src_format, src_value,
|
||||
dest_format, dest_value);
|
||||
return gst_osselement_convert (GST_OSSELEMENT (osssink),
|
||||
src_format, src_value,
|
||||
dest_format, dest_value);
|
||||
}
|
||||
|
||||
static const GstQueryType*
|
||||
|
@ -528,23 +511,13 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G
|
|||
osssink = GST_OSSSINK (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_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:
|
||||
osssink->mute = g_value_get_boolean (value);
|
||||
g_object_notify (G_OBJECT (osssink), "mute");
|
||||
break;
|
||||
case ARG_FRAGMENT:
|
||||
osssink->common.fragment = g_value_get_int (value);
|
||||
gst_osscommon_sync_parms (&osssink->common);
|
||||
GST_OSSELEMENT (osssink)->fragment = g_value_get_int (value);
|
||||
gst_osselement_sync_parms (GST_OSSELEMENT (osssink));
|
||||
break;
|
||||
case ARG_BUFFER_SIZE:
|
||||
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);
|
||||
|
||||
switch (prop_id) {
|
||||
case ARG_DEVICE:
|
||||
g_value_set_string (value, osssink->common.device);
|
||||
break;
|
||||
case ARG_MUTE:
|
||||
g_value_set_boolean (value, osssink->mute);
|
||||
break;
|
||||
case ARG_FRAGMENT:
|
||||
g_value_set_int (value, osssink->common.fragment);
|
||||
g_value_set_int (value, GST_OSSELEMENT (osssink)->fragment);
|
||||
break;
|
||||
case ARG_BUFFER_SIZE:
|
||||
g_value_set_uint (value, osssink->bufsize);
|
||||
|
@ -604,43 +574,23 @@ gst_osssink_change_state (GstElement *element)
|
|||
osssink = GST_OSSSINK (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:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
osssink->resync = TRUE;
|
||||
break;
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
{
|
||||
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);
|
||||
osssink->resync = TRUE;
|
||||
break;
|
||||
}
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN))
|
||||
ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0);
|
||||
gst_osscommon_reset (&osssink->common);
|
||||
ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_RESET, 0);
|
||||
gst_osselement_reset (GST_OSSELEMENT (osssink));
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
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");
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gstosscommon.h"
|
||||
#include "gstosselement.h"
|
||||
#include <gst/audio/audioclock.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
@ -53,7 +53,7 @@ typedef struct _GstOssSink GstOssSink;
|
|||
typedef struct _GstOssSinkClass GstOssSinkClass;
|
||||
|
||||
struct _GstOssSink {
|
||||
GstElement element;
|
||||
GstOssElement element;
|
||||
|
||||
GstPad *sinkpad;
|
||||
GstBufferPool *sinkpool;
|
||||
|
@ -64,12 +64,9 @@ struct _GstOssSink {
|
|||
gboolean sync;
|
||||
guint64 handled;
|
||||
|
||||
GstOssCommon common;
|
||||
|
||||
gboolean mute;
|
||||
guint bufsize;
|
||||
guint chunk_size;
|
||||
|
||||
};
|
||||
|
||||
struct _GstOssSinkClass {
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <gstosssrc.h>
|
||||
#include <gstosscommon.h>
|
||||
#include <gstosselement.h>
|
||||
#include <gst/audio/audioclock.h>
|
||||
|
||||
/* elementfactory information */
|
||||
|
@ -56,7 +56,6 @@ enum {
|
|||
|
||||
enum {
|
||||
ARG_0,
|
||||
ARG_DEVICE,
|
||||
ARG_BUFFERSIZE,
|
||||
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_init (GstOssSrc *osssrc);
|
||||
static void gst_osssrc_dispose (GObject *object);
|
||||
static void gst_osssrc_finalize (GObject *object);
|
||||
|
||||
static GstPadLinkReturn gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps);
|
||||
static const GstFormat* gst_osssrc_get_formats (GstPad *pad);
|
||||
|
@ -136,7 +134,7 @@ gst_osssrc_get_type (void)
|
|||
0,
|
||||
(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;
|
||||
}
|
||||
|
@ -150,14 +148,11 @@ gst_osssrc_class_init (GstOssSrcClass *klass)
|
|||
gobject_class = (GObjectClass*)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_param_spec_ulong ("buffersize","Buffer Size","The size of the buffers with samples",
|
||||
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_param_spec_int ("fragment", "Fragment",
|
||||
"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->get_property = gst_osssrc_get_property;
|
||||
gobject_class->dispose = gst_osssrc_dispose;
|
||||
gobject_class->finalize = gst_osssrc_finalize;
|
||||
|
||||
gstelement_class->change_state = gst_osssrc_change_state;
|
||||
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_osscommon_init (&osssrc->common);
|
||||
|
||||
osssrc->buffersize = 4096;
|
||||
osssrc->curoffset = 0;
|
||||
|
||||
|
@ -202,6 +194,7 @@ gst_osssrc_init (GstOssSrc *osssrc)
|
|||
|
||||
osssrc->clock = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_osssrc_dispose (GObject *object)
|
||||
{
|
||||
|
@ -211,16 +204,6 @@ gst_osssrc_dispose (GObject *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
|
||||
gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps)
|
||||
|
@ -232,10 +215,10 @@ gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps)
|
|||
if (!GST_CAPS_IS_FIXED (caps))
|
||||
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;
|
||||
|
||||
if (!gst_osscommon_sync_parms (&src->common))
|
||||
if (!gst_osselement_sync_parms (GST_OSSELEMENT (src)))
|
||||
return GST_PAD_LINK_REFUSED;
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
|
@ -251,10 +234,10 @@ gst_osssrc_negotiate (GstPad *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;
|
||||
|
||||
if (!gst_osscommon_sync_parms (&src->common))
|
||||
if (!gst_osselement_sync_parms (GST_OSSELEMENT (src)))
|
||||
return FALSE;
|
||||
|
||||
/* set caps on src pad */
|
||||
|
@ -262,12 +245,12 @@ gst_osssrc_negotiate (GstPad *pad)
|
|||
GST_CAPS_NEW (
|
||||
"oss_src",
|
||||
"audio/x-raw-int",
|
||||
"endianness", GST_PROPS_INT (src->common.endianness),
|
||||
"signed", GST_PROPS_BOOLEAN (src->common.sign),
|
||||
"width", GST_PROPS_INT (src->common.width),
|
||||
"depth", GST_PROPS_INT (src->common.depth),
|
||||
"rate", GST_PROPS_INT (src->common.rate),
|
||||
"channels", GST_PROPS_INT (src->common.channels)
|
||||
"endianness", GST_PROPS_INT (GST_OSSELEMENT (src)->endianness),
|
||||
"signed", GST_PROPS_BOOLEAN (GST_OSSELEMENT (src)->sign),
|
||||
"width", GST_PROPS_INT (GST_OSSELEMENT (src)->width),
|
||||
"depth", GST_PROPS_INT (GST_OSSELEMENT (src)->depth),
|
||||
"rate", GST_PROPS_INT (GST_OSSELEMENT (src)->rate),
|
||||
"channels", GST_PROPS_INT (GST_OSSELEMENT (src)->channels)
|
||||
)) <= 0)
|
||||
{
|
||||
return FALSE;
|
||||
|
@ -281,13 +264,13 @@ gst_osssrc_get_time (GstClock *clock, gpointer data)
|
|||
GstOssSrc *osssrc = GST_OSSSRC (data);
|
||||
audio_buf_info info;
|
||||
|
||||
if (!osssrc->common.bps)
|
||||
if (!GST_OSSELEMENT (osssrc)->bps)
|
||||
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 (osssrc->curoffset + info.bytes) * GST_SECOND / osssrc->common.bps;
|
||||
return (osssrc->curoffset + info.bytes) * GST_SECOND / GST_OSSELEMENT (osssrc)->bps;
|
||||
}
|
||||
|
||||
static GstClock*
|
||||
|
@ -336,13 +319,13 @@ gst_osssrc_get (GstPad *pad)
|
|||
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_element_error (GST_ELEMENT (src), "no format negotiated");
|
||||
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);
|
||||
if (readbytes < 0) {
|
||||
gst_buffer_unref (buf);
|
||||
|
@ -361,7 +344,9 @@ gst_osssrc_get (GstPad *pad)
|
|||
GST_BUFFER_OFFSET (buf) = src->curoffset;
|
||||
|
||||
/* 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;
|
||||
|
||||
|
@ -382,13 +367,9 @@ gst_osssrc_set_property (GObject *object, guint prop_id, const GValue *value, GP
|
|||
case ARG_BUFFERSIZE:
|
||||
src->buffersize = g_value_get_ulong (value);
|
||||
break;
|
||||
case ARG_DEVICE:
|
||||
g_free(src->common.device);
|
||||
src->common.device = g_strdup (g_value_get_string (value));
|
||||
break;
|
||||
case ARG_FRAGMENT:
|
||||
src->common.fragment = g_value_get_int (value);
|
||||
gst_osscommon_sync_parms (&src->common);
|
||||
GST_OSSELEMENT (src)->fragment = g_value_get_int (value);
|
||||
gst_osselement_sync_parms (GST_OSSELEMENT (src));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -406,11 +387,8 @@ gst_osssrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSp
|
|||
case ARG_BUFFERSIZE:
|
||||
g_value_set_ulong (value, src->buffersize);
|
||||
break;
|
||||
case ARG_DEVICE:
|
||||
g_value_set_string (value, src->common.device);
|
||||
break;
|
||||
case ARG_FRAGMENT:
|
||||
g_value_set_int (value, src->common.fragment);
|
||||
g_value_set_int (value, GST_OSSELEMENT (src)->fragment);
|
||||
break;
|
||||
default:
|
||||
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");
|
||||
|
||||
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:
|
||||
osssrc->curoffset = 0;
|
||||
break;
|
||||
|
@ -448,14 +415,9 @@ gst_osssrc_change_state (GstElement *element)
|
|||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
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;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
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);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -485,7 +447,7 @@ gst_osssrc_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -521,10 +483,10 @@ gst_osssrc_src_event (GstPad *pad, GstEvent *event)
|
|||
format = GST_FORMAT_BYTES;
|
||||
|
||||
/* convert to bytes */
|
||||
if (gst_osscommon_convert (&osssrc->common,
|
||||
GST_EVENT_SIZE_FORMAT (event),
|
||||
GST_EVENT_SIZE_VALUE (event),
|
||||
&format, &value))
|
||||
if (gst_osselement_convert (GST_OSSELEMENT (osssrc),
|
||||
GST_EVENT_SIZE_FORMAT (event),
|
||||
GST_EVENT_SIZE_VALUE (event),
|
||||
&format, &value))
|
||||
{
|
||||
osssrc->buffersize = GST_EVENT_SIZE_VALUE (event);
|
||||
g_object_notify (G_OBJECT (osssrc), "buffersize");
|
||||
|
@ -567,9 +529,9 @@ gst_osssrc_src_query (GstPad *pad, GstQueryType type, GstFormat *format, gint64
|
|||
|
||||
switch (type) {
|
||||
case GST_QUERY_POSITION:
|
||||
res = gst_osscommon_convert (&osssrc->common,
|
||||
GST_FORMAT_BYTES, osssrc->curoffset,
|
||||
format, value);
|
||||
res = gst_osselement_convert (GST_OSSELEMENT (osssrc),
|
||||
GST_FORMAT_BYTES, osssrc->curoffset,
|
||||
format, value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "gstosscommon.h"
|
||||
#include "gstosselement.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@ -51,13 +51,11 @@ typedef struct _GstOssSrc GstOssSrc;
|
|||
typedef struct _GstOssSrcClass GstOssSrcClass;
|
||||
|
||||
struct _GstOssSrc {
|
||||
GstElement element;
|
||||
GstOssElement element;
|
||||
|
||||
/* pads */
|
||||
GstPad *srcpad;
|
||||
|
||||
GstOssCommon common;
|
||||
|
||||
gboolean need_eos; /* Do we need to emit an EOS? */
|
||||
|
||||
/* blocking */
|
||||
|
|
Loading…
Reference in a new issue