mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 01:00:37 +00:00
More refactoring osssrc has more features now, like query/convert etc
Original commit message from CVS: More refactoring osssrc has more features now, like query/convert etc
This commit is contained in:
parent
f5743b63de
commit
4682001013
6 changed files with 628 additions and 550 deletions
|
@ -21,10 +21,19 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "gstosscommon.h"
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <sys/soundcard.h>
|
#include <sys/soundcard.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
gboolean
|
#include <config.h>
|
||||||
|
#include "gstosscommon.h"
|
||||||
|
|
||||||
|
static gboolean
|
||||||
gst_ossformat_get (gint law, gint endianness, gboolean sign, gint width, gint depth,
|
gst_ossformat_get (gint law, gint endianness, gboolean sign, gint width, gint depth,
|
||||||
gint *format, gint *bps)
|
gint *format, gint *bps)
|
||||||
{
|
{
|
||||||
|
@ -89,3 +98,348 @@ gst_ossformat_get (gint law, gint endianness, gboolean sign, gint width, gint de
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_osscommon_init (GstOssCommon *common)
|
||||||
|
{
|
||||||
|
common->device = g_strdup ("/dev/dsp");
|
||||||
|
common->fd = -1;
|
||||||
|
|
||||||
|
common->law = 0;
|
||||||
|
common->endianness = G_BYTE_ORDER;
|
||||||
|
common->sign = TRUE;
|
||||||
|
common->width = 16;
|
||||||
|
common->depth = 16;
|
||||||
|
common->channels = 2;
|
||||||
|
common->rate = 44100;
|
||||||
|
common->fragment = 6;
|
||||||
|
common->bps = 0;
|
||||||
|
|
||||||
|
/* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
common->format = AFMT_S16_BE;
|
||||||
|
#else
|
||||||
|
common->format = AFMT_S16_LE;
|
||||||
|
#endif /* WORDS_BIGENDIAN */
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_osscommon_parse_caps (GstOssCommon *common, GstCaps *caps)
|
||||||
|
{
|
||||||
|
gint bps, format;
|
||||||
|
|
||||||
|
gst_caps_get_int (caps, "width", &common->width);
|
||||||
|
gst_caps_get_int (caps, "depth", &common->depth);
|
||||||
|
|
||||||
|
if (common->width != common->depth)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
gst_caps_get_int (caps, "law", &common->law);
|
||||||
|
gst_caps_get_int (caps, "endianness", &common->endianness);
|
||||||
|
gst_caps_get_boolean (caps, "signed", &common->sign);
|
||||||
|
|
||||||
|
if (!gst_ossformat_get (common->law, common->endianness, common->sign,
|
||||||
|
common->width, common->depth, &format, &bps))
|
||||||
|
{
|
||||||
|
GST_DEBUG (GST_CAT_PLUGIN_INFO, "could not get format");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_caps_get_int (caps, "channels", &common->channels);
|
||||||
|
gst_caps_get_int (caps, "rate", &common->rate);
|
||||||
|
|
||||||
|
common->bps = bps * common->channels * common->rate;
|
||||||
|
common->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_osscommon_merge_fixed_caps (GstOssCommon *common, GstCaps *caps)
|
||||||
|
{
|
||||||
|
gint bps, format;
|
||||||
|
|
||||||
|
/* peel off fixed stuff from the caps */
|
||||||
|
GET_FIXED_INT (caps, "law", &common->law);
|
||||||
|
GET_FIXED_INT (caps, "endianness", &common->endianness);
|
||||||
|
GET_FIXED_BOOLEAN (caps, "signed", &common->sign);
|
||||||
|
GET_FIXED_INT (caps, "width", &common->width);
|
||||||
|
GET_FIXED_INT (caps, "depth", &common->depth);
|
||||||
|
|
||||||
|
if (!gst_ossformat_get (common->law, common->endianness, common->sign,
|
||||||
|
common->width, common->depth, &format, &bps))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GET_FIXED_INT (caps, "rate", &common->rate);
|
||||||
|
GET_FIXED_INT (caps, "channels", &common->channels);
|
||||||
|
|
||||||
|
common->bps = bps * common->channels * common->rate;
|
||||||
|
common->format = format;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_osscommon_sync_parms (GstOssCommon *common)
|
||||||
|
{
|
||||||
|
audio_buf_info space;
|
||||||
|
int frag;
|
||||||
|
gint target_format;
|
||||||
|
gint target_channels;
|
||||||
|
gint target_rate;
|
||||||
|
gint fragscale, frag_ln;
|
||||||
|
|
||||||
|
if (common->fd == -1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (common->fragment >> 16)
|
||||||
|
frag = common->fragment;
|
||||||
|
else
|
||||||
|
frag = 0x7FFF0000 | common->fragment;
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_PLUGIN_INFO,
|
||||||
|
"common: setting sound card to %dHz %d format %s (%08x fragment)",
|
||||||
|
common->rate, common->format,
|
||||||
|
(common->channels == 2) ? "stereo" : "mono", frag);
|
||||||
|
|
||||||
|
ioctl (common->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
|
||||||
|
ioctl (common->fd, SNDCTL_DSP_RESET, 0);
|
||||||
|
|
||||||
|
target_format = common->format;
|
||||||
|
target_channels = common->channels;
|
||||||
|
target_rate = common->rate;
|
||||||
|
|
||||||
|
ioctl (common->fd, SNDCTL_DSP_SETFMT, &common->format);
|
||||||
|
ioctl (common->fd, SNDCTL_DSP_CHANNELS, &common->channels);
|
||||||
|
ioctl (common->fd, SNDCTL_DSP_SPEED, &common->rate);
|
||||||
|
|
||||||
|
ioctl (common->fd, SNDCTL_DSP_GETBLKSIZE, &common->fragment_size);
|
||||||
|
|
||||||
|
if (common->mode == GST_OSSCOMMON_WRITE) {
|
||||||
|
ioctl (common->fd, SNDCTL_DSP_GETOSPACE, &space);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ioctl (common->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++;
|
||||||
|
}
|
||||||
|
common->fragment = space.fragstotal << 16 | frag_ln;
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_PLUGIN_INFO,
|
||||||
|
"common: set sound card to %dHz, %d format, %s "
|
||||||
|
"(%d bytes buffer, %08x fragment)",
|
||||||
|
common->rate, common->format,
|
||||||
|
(common->channels == 2) ? "stereo" : "mono",
|
||||||
|
space.bytes, common->fragment);
|
||||||
|
|
||||||
|
common->fragment_time = (GST_SECOND * common->fragment_size) / common->bps;
|
||||||
|
GST_INFO (GST_CAT_PLUGIN_INFO, "fragment time %u %llu\n",
|
||||||
|
common->bps, common->fragment_time);
|
||||||
|
|
||||||
|
if (target_format != common->format ||
|
||||||
|
target_channels != common->channels ||
|
||||||
|
target_rate != common->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_osscommon_open_audio (GstOssCommon *common, GstOssOpenMode mode, gchar **error)
|
||||||
|
{
|
||||||
|
gint caps;
|
||||||
|
g_return_val_if_fail (common->fd == -1, FALSE);
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_PLUGIN_INFO, "common: attempting to open sound device");
|
||||||
|
|
||||||
|
/* first try to open the sound card */
|
||||||
|
/* FIXME: this code is dubious, why do we need to open and close this ?*/
|
||||||
|
if (mode == GST_OSSCOMMON_WRITE) {
|
||||||
|
common->fd = open (common->device, O_WRONLY | O_NONBLOCK);
|
||||||
|
if (errno == EBUSY) {
|
||||||
|
g_warning ("osscommon: unable to open the sound device (in use ?)\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (common->fd >= 0)
|
||||||
|
close (common->fd);
|
||||||
|
|
||||||
|
/* re-open the sound device in blocking mode */
|
||||||
|
common->fd = open (common->device, O_WRONLY);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
common->fd = open (common->device, O_RDONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (common->fd < 0) {
|
||||||
|
switch (errno) {
|
||||||
|
case EISDIR:
|
||||||
|
*error = g_strdup_printf ("osscommon: Device %s is a directory",
|
||||||
|
common->device);
|
||||||
|
break;
|
||||||
|
case EACCES:
|
||||||
|
case ETXTBSY:
|
||||||
|
*error = g_strdup_printf ( "osscommon: Cannot access %s, check permissions",
|
||||||
|
common->device);
|
||||||
|
break;
|
||||||
|
case ENXIO:
|
||||||
|
case ENODEV:
|
||||||
|
case ENOENT:
|
||||||
|
*error = g_strdup_printf ("osscommon: Cannot access %s, does it exist ?",
|
||||||
|
common->device);
|
||||||
|
break;
|
||||||
|
case EROFS:
|
||||||
|
*error = g_strdup_printf ("osscommon: Cannot access %s, read-only filesystem ?",
|
||||||
|
common->device);
|
||||||
|
default:
|
||||||
|
/* FIXME: strerror is not threadsafe */
|
||||||
|
*error = g_strdup_printf ("osscommon: Cannot open %s, generic error: %s",
|
||||||
|
common->device, strerror (errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
common->mode = mode;
|
||||||
|
|
||||||
|
/* we have it, set the default parameters and go have fun */
|
||||||
|
/* set card state */
|
||||||
|
ioctl (common->fd, SNDCTL_DSP_GETCAPS, &caps);
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Capabilities %08x", caps);
|
||||||
|
|
||||||
|
if (caps & DSP_CAP_DUPLEX) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Full duplex");
|
||||||
|
if (caps & DSP_CAP_REALTIME) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Realtime");
|
||||||
|
if (caps & DSP_CAP_BATCH) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Batch");
|
||||||
|
if (caps & DSP_CAP_COPROC) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Has coprocessor");
|
||||||
|
if (caps & DSP_CAP_TRIGGER) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Trigger");
|
||||||
|
if (caps & DSP_CAP_MMAP) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Direct access");
|
||||||
|
|
||||||
|
#ifdef DSP_CAP_MULTI
|
||||||
|
if (caps & DSP_CAP_MULTI) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Multiple open");
|
||||||
|
#endif /* DSP_CAP_MULTI */
|
||||||
|
|
||||||
|
#ifdef DSP_CAP_BIND
|
||||||
|
if (caps & DSP_CAP_BIND) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Channel binding");
|
||||||
|
#endif /* DSP_CAP_BIND */
|
||||||
|
|
||||||
|
ioctl(common->fd, SNDCTL_DSP_GETFMTS, &caps);
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Formats %08x", caps);
|
||||||
|
if (caps & AFMT_MU_LAW) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: MU_LAW");
|
||||||
|
if (caps & AFMT_A_LAW) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: A_LAW");
|
||||||
|
if (caps & AFMT_IMA_ADPCM) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: IMA_ADPCM");
|
||||||
|
if (caps & AFMT_U8) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: U8");
|
||||||
|
if (caps & AFMT_S16_LE) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: S16_LE");
|
||||||
|
if (caps & AFMT_S16_BE) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: S16_BE");
|
||||||
|
if (caps & AFMT_S8) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: S8");
|
||||||
|
if (caps & AFMT_U16_LE) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: U16_LE");
|
||||||
|
if (caps & AFMT_U16_BE) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: U16_BE");
|
||||||
|
if (caps & AFMT_MPEG) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: MPEG");
|
||||||
|
#ifdef AFMT_AC3
|
||||||
|
if (caps & AFMT_AC3) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: AC3");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_PLUGIN_INFO,
|
||||||
|
"osscommon: opened audio (%s) with fd=%d", common->device, common->fd);
|
||||||
|
|
||||||
|
common->caps = caps;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_osscommon_close_audio (GstOssCommon *common)
|
||||||
|
{
|
||||||
|
if (common->fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
close(common->fd);
|
||||||
|
common->fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_osscommon_convert (GstOssCommon *common, 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 (common->bps == 0 || common->channels == 0 || common->width == 0)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
switch (src_format) {
|
||||||
|
case GST_FORMAT_BYTES:
|
||||||
|
switch (*dest_format) {
|
||||||
|
case GST_FORMAT_DEFAULT:
|
||||||
|
*dest_format = GST_FORMAT_TIME;
|
||||||
|
case GST_FORMAT_TIME:
|
||||||
|
*dest_value = src_value * GST_SECOND / common->bps;
|
||||||
|
break;
|
||||||
|
case GST_FORMAT_UNITS:
|
||||||
|
*dest_value = src_value / (common->channels * common->width);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_FORMAT_TIME:
|
||||||
|
switch (*dest_format) {
|
||||||
|
case GST_FORMAT_DEFAULT:
|
||||||
|
*dest_format = GST_FORMAT_BYTES;
|
||||||
|
case GST_FORMAT_BYTES:
|
||||||
|
*dest_value = src_value * common->bps / GST_SECOND;
|
||||||
|
break;
|
||||||
|
case GST_FORMAT_UNITS:
|
||||||
|
*dest_value = src_value * common->rate / GST_SECOND;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GST_FORMAT_UNITS:
|
||||||
|
switch (*dest_format) {
|
||||||
|
case GST_FORMAT_DEFAULT:
|
||||||
|
*dest_format = GST_FORMAT_TIME;
|
||||||
|
case GST_FORMAT_TIME:
|
||||||
|
*dest_value = src_value * GST_SECOND / common->rate;
|
||||||
|
break;
|
||||||
|
case GST_FORMAT_BYTES:
|
||||||
|
*dest_value = src_value * common->channels * common->width;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,12 +20,57 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __GST_OSSFORMAT_H__
|
#ifndef __GST_OSSCOMMON_H__
|
||||||
#define __GST_OSSFORMAT_H__
|
#define __GST_OSSCOMMON_H__
|
||||||
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
gboolean gst_ossformat_get (gint law, gint endianness, gboolean sign,
|
typedef struct _GstOssCommon GstOssCommon;
|
||||||
gint width, gint depth, gint *format, gint *bps);
|
|
||||||
|
|
||||||
#endif /* __GST_OSSFORMAT_H__ */
|
typedef enum {
|
||||||
|
GST_OSSCOMMON_READ,
|
||||||
|
GST_OSSCOMMON_WRITE,
|
||||||
|
} GstOssOpenMode;
|
||||||
|
|
||||||
|
struct _GstOssCommon
|
||||||
|
{
|
||||||
|
gchar *device;
|
||||||
|
/* 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
void gst_osscommon_init (GstOssCommon *common);
|
||||||
|
|
||||||
|
gboolean gst_osscommon_open_audio (GstOssCommon *common,
|
||||||
|
GstOssOpenMode mode, gchar **error);
|
||||||
|
void gst_osscommon_close_audio (GstOssCommon *common);
|
||||||
|
|
||||||
|
gboolean gst_osscommon_parse_caps (GstOssCommon *common, GstCaps *caps);
|
||||||
|
gboolean gst_osscommon_merge_fixed_caps (GstOssCommon *common, GstCaps *caps);
|
||||||
|
|
||||||
|
gboolean gst_osscommon_sync_parms (GstOssCommon *common);
|
||||||
|
|
||||||
|
gboolean gst_osscommon_convert (GstOssCommon *common,
|
||||||
|
GstFormat src_format, gint64 src_value,
|
||||||
|
GstFormat *dest_format, gint64 *dest_value);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __GST_OSSCOMMON_H__ */
|
||||||
|
|
|
@ -20,18 +20,10 @@
|
||||||
* Boston, MA 02111-1307, USA.
|
* Boston, MA 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/soundcard.h>
|
#include <sys/soundcard.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <gstosssink.h>
|
#include <gstosssink.h>
|
||||||
#include <gstosscommon.h>
|
|
||||||
|
|
||||||
/* elementfactory information */
|
/* elementfactory information */
|
||||||
static GstElementDetails gst_osssink_details = {
|
static GstElementDetails gst_osssink_details = {
|
||||||
|
@ -49,9 +41,6 @@ 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_finalize (GObject *object);
|
static void gst_osssink_finalize (GObject *object);
|
||||||
|
|
||||||
static gboolean gst_osssink_open_audio (GstOssSink *sink);
|
|
||||||
static void gst_osssink_close_audio (GstOssSink *sink);
|
|
||||||
static gboolean gst_osssink_sync_parms (GstOssSink *osssink);
|
|
||||||
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);
|
||||||
static GstClock* gst_osssink_get_clock (GstElement *element);
|
static GstClock* gst_osssink_get_clock (GstElement *element);
|
||||||
|
@ -163,7 +152,7 @@ gst_osssink_finalize (GObject *object)
|
||||||
{
|
{
|
||||||
GstOssSink *osssink = (GstOssSink *) object;
|
GstOssSink *osssink = (GstOssSink *) object;
|
||||||
|
|
||||||
g_free (osssink->device);
|
g_free (osssink->common.device);
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -227,19 +216,9 @@ 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);
|
||||||
|
|
||||||
osssink->device = g_strdup ("/dev/dsp");
|
gst_osscommon_init (&osssink->common);
|
||||||
osssink->fd = -1;
|
|
||||||
osssink->channels = 1;
|
|
||||||
osssink->frequency = 11025;
|
|
||||||
osssink->fragment = 6;
|
|
||||||
/* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
osssink->format = AFMT_S16_BE;
|
|
||||||
#else
|
|
||||||
osssink->format = AFMT_S16_LE;
|
|
||||||
#endif /* WORDS_BIGENDIAN */
|
|
||||||
osssink->bufsize = 4096;
|
osssink->bufsize = 4096;
|
||||||
osssink->bps = 0;
|
|
||||||
osssink->resync = FALSE;
|
osssink->resync = FALSE;
|
||||||
osssink->sync = TRUE;
|
osssink->sync = TRUE;
|
||||||
osssink->sinkpool = NULL;
|
osssink->sinkpool = NULL;
|
||||||
|
@ -254,141 +233,32 @@ gst_osssink_init (GstOssSink *osssink)
|
||||||
static GstPadConnectReturn
|
static GstPadConnectReturn
|
||||||
gst_osssink_sinkconnect (GstPad *pad, GstCaps *caps)
|
gst_osssink_sinkconnect (GstPad *pad, GstCaps *caps)
|
||||||
{
|
{
|
||||||
gint law, endianness, width, depth, bps;
|
|
||||||
gboolean sign;
|
|
||||||
gint format = -1;
|
|
||||||
GstOssSink *osssink = GST_OSSSINK (gst_pad_get_parent (pad));
|
GstOssSink *osssink = GST_OSSSINK (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
if (!GST_CAPS_IS_FIXED (caps))
|
if (!GST_CAPS_IS_FIXED (caps))
|
||||||
return GST_PAD_CONNECT_DELAYED;
|
return GST_PAD_CONNECT_DELAYED;
|
||||||
|
|
||||||
gst_caps_get_int (caps, "width", &width);
|
|
||||||
gst_caps_get_int (caps, "depth", &depth);
|
|
||||||
|
|
||||||
if (width != depth)
|
if (!gst_osscommon_parse_caps (&osssink->common, caps))
|
||||||
return GST_PAD_CONNECT_REFUSED;
|
return GST_PAD_CONNECT_REFUSED;
|
||||||
|
|
||||||
osssink->width = width;
|
if (!gst_osscommon_sync_parms (&osssink->common)) {
|
||||||
|
|
||||||
/* laws 1 and 2 are 1 bps anyway */
|
|
||||||
osssink->bps = 1;
|
|
||||||
|
|
||||||
gst_caps_get_int (caps, "law", &law);
|
|
||||||
gst_caps_get_int (caps, "endianness", &endianness);
|
|
||||||
gst_caps_get_boolean (caps, "signed", &sign);
|
|
||||||
|
|
||||||
if (!gst_ossformat_get (law, endianness, sign,
|
|
||||||
width, depth, &format, &bps))
|
|
||||||
{
|
|
||||||
GST_DEBUG (GST_CAT_PLUGIN_INFO, "could not get format");
|
|
||||||
return GST_PAD_CONNECT_REFUSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
osssink->bps = bps;
|
|
||||||
osssink->format = format;
|
|
||||||
|
|
||||||
gst_caps_get_int (caps, "channels", &osssink->channels);
|
|
||||||
gst_caps_get_int (caps, "rate", &osssink->frequency);
|
|
||||||
|
|
||||||
osssink->bps *= osssink->channels;
|
|
||||||
osssink->bps *= osssink->frequency;
|
|
||||||
|
|
||||||
if (!gst_osssink_sync_parms (osssink)) {
|
|
||||||
return GST_PAD_CONNECT_REFUSED;
|
return GST_PAD_CONNECT_REFUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GST_PAD_CONNECT_OK;
|
return GST_PAD_CONNECT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_osssink_sync_parms (GstOssSink *osssink)
|
|
||||||
{
|
|
||||||
audio_buf_info ospace;
|
|
||||||
int frag;
|
|
||||||
gint target_format;
|
|
||||||
gint target_channels;
|
|
||||||
gint target_frequency;
|
|
||||||
GObject *object;
|
|
||||||
gint fragscale, frag_ln;
|
|
||||||
|
|
||||||
g_return_val_if_fail (osssink != NULL, FALSE);
|
|
||||||
g_return_val_if_fail (GST_IS_OSSSINK (osssink), FALSE);
|
|
||||||
|
|
||||||
if (osssink->fd == -1)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (osssink->fragment >> 16)
|
|
||||||
frag = osssink->fragment;
|
|
||||||
else
|
|
||||||
frag = 0x7FFF0000 | osssink->fragment;
|
|
||||||
|
|
||||||
GST_INFO (GST_CAT_PLUGIN_INFO,
|
|
||||||
"osssink: setting sound card to %dHz %d format %s (%08x fragment)",
|
|
||||||
osssink->frequency, osssink->format,
|
|
||||||
(osssink->channels == 2) ? "stereo" : "mono", frag);
|
|
||||||
|
|
||||||
ioctl (osssink->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
|
|
||||||
|
|
||||||
ioctl (osssink->fd, SNDCTL_DSP_RESET, 0);
|
|
||||||
|
|
||||||
target_format = osssink->format;
|
|
||||||
target_channels = osssink->channels;
|
|
||||||
target_frequency = osssink->frequency;
|
|
||||||
|
|
||||||
ioctl (osssink->fd, SNDCTL_DSP_SETFMT, &osssink->format);
|
|
||||||
ioctl (osssink->fd, SNDCTL_DSP_CHANNELS, &osssink->channels);
|
|
||||||
ioctl (osssink->fd, SNDCTL_DSP_SPEED, &osssink->frequency);
|
|
||||||
|
|
||||||
ioctl (osssink->fd, SNDCTL_DSP_GETBLKSIZE, &osssink->fragment_size);
|
|
||||||
ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &ospace);
|
|
||||||
|
|
||||||
/* calculate new fragment using a poor man's logarithm function */
|
|
||||||
fragscale = 1;
|
|
||||||
frag_ln = 0;
|
|
||||||
while (fragscale < ospace.fragsize) {
|
|
||||||
fragscale <<= 1;
|
|
||||||
frag_ln++;
|
|
||||||
}
|
|
||||||
osssink->fragment = ospace.fragstotal << 16 | frag_ln;
|
|
||||||
|
|
||||||
GST_INFO (GST_CAT_PLUGIN_INFO,
|
|
||||||
"osssink: set sound card to %dHz %d format %s "
|
|
||||||
"(%d bytes buffer, %08x fragment)",
|
|
||||||
osssink->frequency, osssink->format,
|
|
||||||
(osssink->channels == 2) ? "stereo" : "mono",
|
|
||||||
ospace.bytes, osssink->fragment);
|
|
||||||
|
|
||||||
object = G_OBJECT (osssink);
|
|
||||||
g_object_freeze_notify (object);
|
|
||||||
g_object_notify (object, "fragment");
|
|
||||||
g_object_thaw_notify (object);
|
|
||||||
|
|
||||||
osssink->fragment_time = (GST_SECOND * osssink->fragment_size) / osssink->bps;
|
|
||||||
GST_INFO (GST_CAT_PLUGIN_INFO, "fragment time %u %llu\n",
|
|
||||||
osssink->bps, osssink->fragment_time);
|
|
||||||
|
|
||||||
if (target_format != osssink->format ||
|
|
||||||
target_channels != osssink->channels ||
|
|
||||||
target_frequency != osssink->frequency)
|
|
||||||
{
|
|
||||||
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 inline gint64
|
static inline gint64
|
||||||
gst_osssink_get_delay (GstOssSink *osssink)
|
gst_osssink_get_delay (GstOssSink *osssink)
|
||||||
{
|
{
|
||||||
gint delay = 0;
|
gint delay = 0;
|
||||||
|
|
||||||
if (osssink->fd == -1)
|
if (osssink->common.fd == -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (ioctl (osssink->fd, SNDCTL_DSP_GETODELAY, &delay) < 0) {
|
if (ioctl (osssink->common.fd, SNDCTL_DSP_GETODELAY, &delay) < 0) {
|
||||||
audio_buf_info info;
|
audio_buf_info info;
|
||||||
if (ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
|
if (ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
|
||||||
delay = 0;
|
delay = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -405,7 +275,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data)
|
||||||
gint delay;
|
gint delay;
|
||||||
GstClockTime res;
|
GstClockTime res;
|
||||||
|
|
||||||
if (!osssink->bps)
|
if (!osssink->common.bps)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
delay = gst_osssink_get_delay (osssink);
|
delay = gst_osssink_get_delay (osssink);
|
||||||
|
@ -416,7 +286,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->bps;
|
res = (osssink->handled - delay) * GST_SECOND / osssink->common.bps;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -455,7 +325,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->fd, SNDCTL_DSP_SYNC);
|
ioctl (osssink->common.fd, SNDCTL_DSP_SYNC);
|
||||||
gst_oss_clock_set_active (osssink->provided_clock, FALSE);
|
gst_oss_clock_set_active (osssink->provided_clock, FALSE);
|
||||||
gst_pad_event_default (pad, event);
|
gst_pad_event_default (pad, event);
|
||||||
return;
|
return;
|
||||||
|
@ -466,7 +336,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
||||||
{
|
{
|
||||||
gint64 value;
|
gint64 value;
|
||||||
|
|
||||||
ioctl (osssink->fd, SNDCTL_DSP_RESET);
|
ioctl (osssink->common.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_oss_clock_set_active (osssink->provided_clock, FALSE);
|
gst_oss_clock_set_active (osssink->provided_clock, FALSE);
|
||||||
|
@ -483,7 +353,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!osssink->bps) {
|
if (!osssink->common.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;
|
||||||
|
@ -491,7 +361,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
||||||
|
|
||||||
buftime = GST_BUFFER_TIMESTAMP (buf);
|
buftime = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
|
||||||
if (osssink->fd >= 0) {
|
if (osssink->common.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);
|
||||||
|
@ -502,7 +372,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->bps;
|
queued = delay * GST_SECOND / osssink->common.bps;
|
||||||
|
|
||||||
if (osssink->resync && osssink->sync) {
|
if (osssink->resync && osssink->sync) {
|
||||||
gst_element_clock_wait (GST_ELEMENT (osssink), osssink->clock,
|
gst_element_clock_wait (GST_ELEMENT (osssink), osssink->clock,
|
||||||
|
@ -510,14 +380,14 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
||||||
|
|
||||||
if (jitter >= 0) {
|
if (jitter >= 0) {
|
||||||
gst_clock_handle_discont (osssink->clock, buftime - queued + jitter);
|
gst_clock_handle_discont (osssink->clock, buftime - queued + jitter);
|
||||||
write (osssink->fd, data, size);
|
write (osssink->common.fd, data, size);
|
||||||
gst_oss_clock_set_active (osssink->provided_clock, TRUE);
|
gst_oss_clock_set_active (osssink->provided_clock, TRUE);
|
||||||
osssink->resync = FALSE;
|
osssink->resync = FALSE;
|
||||||
osssink->handled += size;
|
osssink->handled += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
write (osssink->fd, data, size);
|
write (osssink->common.fd, data, size);
|
||||||
osssink->handled += size;
|
osssink->handled += size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -525,10 +395,10 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf)
|
||||||
else {
|
else {
|
||||||
audio_buf_info ospace;
|
audio_buf_info ospace;
|
||||||
|
|
||||||
ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &ospace);
|
ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &ospace);
|
||||||
|
|
||||||
if (ospace.bytes >= size) {
|
if (ospace.bytes >= size) {
|
||||||
write (osssink->fd, data, size);
|
write (osssink->common.fd, data, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -552,68 +422,12 @@ static gboolean
|
||||||
gst_osssink_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
|
gst_osssink_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
|
||||||
GstFormat *dest_format, gint64 *dest_value)
|
GstFormat *dest_format, gint64 *dest_value)
|
||||||
{
|
{
|
||||||
gboolean res = TRUE;
|
|
||||||
|
|
||||||
GstOssSink *osssink;
|
GstOssSink *osssink;
|
||||||
|
|
||||||
if (src_format == *dest_format) {
|
|
||||||
*dest_value = src_value;
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
osssink = GST_OSSSINK (gst_pad_get_parent (pad));
|
osssink = GST_OSSSINK (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
if (osssink->bps == 0 || osssink->channels == 0 || osssink->width == 0)
|
return gst_osscommon_convert (&osssink->common, src_format, src_value,
|
||||||
return FALSE;
|
dest_format, dest_value);
|
||||||
|
|
||||||
switch (src_format) {
|
|
||||||
case GST_FORMAT_BYTES:
|
|
||||||
switch (*dest_format) {
|
|
||||||
case GST_FORMAT_DEFAULT:
|
|
||||||
*dest_format = GST_FORMAT_TIME;
|
|
||||||
case GST_FORMAT_TIME:
|
|
||||||
*dest_value = src_value * GST_SECOND / osssink->bps;
|
|
||||||
break;
|
|
||||||
case GST_FORMAT_UNITS:
|
|
||||||
*dest_value = src_value / (osssink->channels * osssink->width);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
res = FALSE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GST_FORMAT_TIME:
|
|
||||||
switch (*dest_format) {
|
|
||||||
case GST_FORMAT_DEFAULT:
|
|
||||||
*dest_format = GST_FORMAT_BYTES;
|
|
||||||
case GST_FORMAT_BYTES:
|
|
||||||
*dest_value = src_value * osssink->bps / GST_SECOND;
|
|
||||||
break;
|
|
||||||
case GST_FORMAT_UNITS:
|
|
||||||
*dest_value = src_value * osssink->frequency / GST_SECOND;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
res = FALSE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GST_FORMAT_UNITS:
|
|
||||||
switch (*dest_format) {
|
|
||||||
case GST_FORMAT_DEFAULT:
|
|
||||||
*dest_format = GST_FORMAT_TIME;
|
|
||||||
case GST_FORMAT_TIME:
|
|
||||||
*dest_value = src_value * GST_SECOND / osssink->frequency;
|
|
||||||
break;
|
|
||||||
case GST_FORMAT_BYTES:
|
|
||||||
*dest_value = src_value * osssink->channels * osssink->width;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
res = FALSE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
res = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const GstPadQueryType*
|
static const GstPadQueryType*
|
||||||
|
@ -673,9 +487,6 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G
|
||||||
{
|
{
|
||||||
GstOssSink *osssink;
|
GstOssSink *osssink;
|
||||||
|
|
||||||
/* it's not null if we got it, but it might not be ours */
|
|
||||||
g_return_if_fail (GST_IS_OSSSINK (object));
|
|
||||||
|
|
||||||
osssink = GST_OSSSINK (object);
|
osssink = GST_OSSSINK (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
|
@ -684,8 +495,8 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G
|
||||||
get_property("device") should return the right one */
|
get_property("device") should return the right one */
|
||||||
if (!GST_FLAG_IS_SET (osssink, GST_OSSSINK_OPEN))
|
if (!GST_FLAG_IS_SET (osssink, GST_OSSSINK_OPEN))
|
||||||
{
|
{
|
||||||
g_free (osssink->device);
|
g_free (osssink->common.device);
|
||||||
osssink->device = g_strdup (g_value_get_string (value));
|
osssink->common.device = g_strdup (g_value_get_string (value));
|
||||||
g_object_notify (object, "device");
|
g_object_notify (object, "device");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -694,8 +505,8 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G
|
||||||
g_object_notify (G_OBJECT (osssink), "mute");
|
g_object_notify (G_OBJECT (osssink), "mute");
|
||||||
break;
|
break;
|
||||||
case ARG_FRAGMENT:
|
case ARG_FRAGMENT:
|
||||||
osssink->fragment = g_value_get_int (value);
|
osssink->common.fragment = g_value_get_int (value);
|
||||||
gst_osssink_sync_parms (osssink);
|
gst_osscommon_sync_parms (&osssink->common);
|
||||||
break;
|
break;
|
||||||
case ARG_BUFFER_SIZE:
|
case ARG_BUFFER_SIZE:
|
||||||
if (osssink->bufsize == g_value_get_int (value)) break;
|
if (osssink->bufsize == g_value_get_int (value)) break;
|
||||||
|
@ -718,20 +529,17 @@ gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamS
|
||||||
{
|
{
|
||||||
GstOssSink *osssink;
|
GstOssSink *osssink;
|
||||||
|
|
||||||
/* it's not null if we got it, but it might not be ours */
|
|
||||||
g_return_if_fail (GST_IS_OSSSINK (object));
|
|
||||||
|
|
||||||
osssink = GST_OSSSINK (object);
|
osssink = GST_OSSSINK (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_DEVICE:
|
case ARG_DEVICE:
|
||||||
g_value_set_string (value, osssink->device);
|
g_value_set_string (value, osssink->common.device);
|
||||||
break;
|
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->fragment);
|
g_value_set_int (value, osssink->common.fragment);
|
||||||
break;
|
break;
|
||||||
case ARG_BUFFER_SIZE:
|
case ARG_BUFFER_SIZE:
|
||||||
g_value_set_int (value, osssink->bufsize);
|
g_value_set_int (value, osssink->bufsize);
|
||||||
|
@ -745,132 +553,24 @@ gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_osssink_open_audio (GstOssSink *sink)
|
|
||||||
{
|
|
||||||
gint caps;
|
|
||||||
g_return_val_if_fail (sink->fd == -1, FALSE);
|
|
||||||
|
|
||||||
GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: attempting to open sound device");
|
|
||||||
|
|
||||||
/* first try to open the sound card */
|
|
||||||
/* FIXME: this code is dubious, why do we need to open and close this ?*/
|
|
||||||
sink->fd = open (sink->device, O_WRONLY | O_NONBLOCK);
|
|
||||||
if (errno == EBUSY) {
|
|
||||||
g_warning ("osssink: unable to open the sound device (in use ?)\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sink->fd >= 0)
|
|
||||||
close (sink->fd);
|
|
||||||
|
|
||||||
/* re-open the sound device in blocking mode */
|
|
||||||
sink->fd = open (sink->device, O_WRONLY);
|
|
||||||
|
|
||||||
if (sink->fd < 0) {
|
|
||||||
switch (errno) {
|
|
||||||
case EISDIR:
|
|
||||||
gst_element_error (GST_ELEMENT (sink),
|
|
||||||
"osssink: Device %s is a directory",
|
|
||||||
sink->device);
|
|
||||||
break;
|
|
||||||
case EACCES:
|
|
||||||
case ETXTBSY:
|
|
||||||
gst_element_error (GST_ELEMENT (sink),
|
|
||||||
"osssink: Cannot access %s, check permissions",
|
|
||||||
sink->device);
|
|
||||||
break;
|
|
||||||
case ENXIO:
|
|
||||||
case ENODEV:
|
|
||||||
case ENOENT:
|
|
||||||
gst_element_error (GST_ELEMENT (sink),
|
|
||||||
"osssink: Cannot access %s, does it exist ?",
|
|
||||||
sink->device);
|
|
||||||
break;
|
|
||||||
case EROFS:
|
|
||||||
gst_element_error (GST_ELEMENT (sink),
|
|
||||||
"osssink: Cannot access %s, read-only filesystem ?",
|
|
||||||
sink->device);
|
|
||||||
default:
|
|
||||||
/* FIXME: strerror is not threadsafe */
|
|
||||||
gst_element_error (GST_ELEMENT (sink),
|
|
||||||
"osssink: Cannot open %s, generic error: %s",
|
|
||||||
sink->device, strerror (errno));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
/* we have it, set the default parameters and go have fun */
|
|
||||||
/* set card state */
|
|
||||||
ioctl (sink->fd, SNDCTL_DSP_GETCAPS, &caps);
|
|
||||||
|
|
||||||
GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Capabilities %08x", caps);
|
|
||||||
|
|
||||||
if (caps & DSP_CAP_DUPLEX) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Full duplex");
|
|
||||||
if (caps & DSP_CAP_REALTIME) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Realtime");
|
|
||||||
if (caps & DSP_CAP_BATCH) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Batch");
|
|
||||||
if (caps & DSP_CAP_COPROC) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Has coprocessor");
|
|
||||||
if (caps & DSP_CAP_TRIGGER) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Trigger");
|
|
||||||
if (caps & DSP_CAP_MMAP) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Direct access");
|
|
||||||
|
|
||||||
#ifdef DSP_CAP_MULTI
|
|
||||||
if (caps & DSP_CAP_MULTI) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Multiple open");
|
|
||||||
#endif /* DSP_CAP_MULTI */
|
|
||||||
|
|
||||||
#ifdef DSP_CAP_BIND
|
|
||||||
if (caps & DSP_CAP_BIND) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Channel binding");
|
|
||||||
#endif /* DSP_CAP_BIND */
|
|
||||||
|
|
||||||
ioctl(sink->fd, SNDCTL_DSP_GETFMTS, &caps);
|
|
||||||
|
|
||||||
GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Formats %08x", caps);
|
|
||||||
if (caps & AFMT_MU_LAW) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: MU_LAW");
|
|
||||||
if (caps & AFMT_A_LAW) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: A_LAW");
|
|
||||||
if (caps & AFMT_IMA_ADPCM) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: IMA_ADPCM");
|
|
||||||
if (caps & AFMT_U8) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: U8");
|
|
||||||
if (caps & AFMT_S16_LE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: S16_LE");
|
|
||||||
if (caps & AFMT_S16_BE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: S16_BE");
|
|
||||||
if (caps & AFMT_S8) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: S8");
|
|
||||||
if (caps & AFMT_U16_LE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: U16_LE");
|
|
||||||
if (caps & AFMT_U16_BE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: U16_BE");
|
|
||||||
if (caps & AFMT_MPEG) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: MPEG");
|
|
||||||
#ifdef AFMT_AC3
|
|
||||||
if (caps & AFMT_AC3) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: AC3");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: opened audio (%s) with fd=%d", sink->device, sink->fd);
|
|
||||||
GST_FLAG_SET (sink, GST_OSSSINK_OPEN);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_osssink_close_audio (GstOssSink *sink)
|
|
||||||
{
|
|
||||||
if (sink->fd < 0) return;
|
|
||||||
|
|
||||||
close(sink->fd);
|
|
||||||
sink->fd = -1;
|
|
||||||
|
|
||||||
GST_FLAG_UNSET (sink, GST_OSSSINK_OPEN);
|
|
||||||
|
|
||||||
GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: closed sound device");
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_osssink_change_state (GstElement *element)
|
gst_osssink_change_state (GstElement *element)
|
||||||
{
|
{
|
||||||
GstOssSink *osssink;
|
GstOssSink *osssink;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_OSSSINK (element), FALSE);
|
|
||||||
|
|
||||||
osssink = GST_OSSSINK (element);
|
osssink = GST_OSSSINK (element);
|
||||||
|
|
||||||
switch (GST_STATE_TRANSITION (element)) {
|
switch (GST_STATE_TRANSITION (element)) {
|
||||||
case GST_STATE_NULL_TO_READY:
|
case GST_STATE_NULL_TO_READY:
|
||||||
if (!GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) {
|
if (!GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) {
|
||||||
if (!gst_osssink_open_audio (osssink)) {
|
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;
|
return GST_STATE_FAILURE;
|
||||||
}
|
}
|
||||||
|
GST_FLAG_SET (element, GST_OSSSINK_OPEN);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
|
@ -881,18 +581,23 @@ gst_osssink_change_state (GstElement *element)
|
||||||
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->fd, SNDCTL_DSP_RESET, 0);
|
ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0);
|
||||||
gst_oss_clock_set_active (osssink->provided_clock, FALSE);
|
gst_oss_clock_set_active (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->fd, SNDCTL_DSP_RESET, 0);
|
ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0);
|
||||||
|
gst_osscommon_init (&osssink->common);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_NULL:
|
case GST_STATE_READY_TO_NULL:
|
||||||
if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN))
|
if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) {
|
||||||
gst_osssink_close_audio (osssink);
|
gst_osscommon_close_audio (&osssink->common);
|
||||||
|
GST_FLAG_UNSET (osssink, GST_OSSSINK_OPEN);
|
||||||
|
|
||||||
|
GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: closed sound device");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,15 +25,12 @@
|
||||||
#define __GST_OSSSINK_H__
|
#define __GST_OSSSINK_H__
|
||||||
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
|
||||||
|
#include "gstosscommon.h"
|
||||||
#include "gstossclock.h"
|
#include "gstossclock.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_BEGIN_DECLS
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
|
|
||||||
#define GST_TYPE_OSSSINK \
|
#define GST_TYPE_OSSSINK \
|
||||||
(gst_osssink_get_type())
|
(gst_osssink_get_type())
|
||||||
|
@ -67,23 +64,11 @@ struct _GstOssSink {
|
||||||
gboolean sync;
|
gboolean sync;
|
||||||
guint64 handled;
|
guint64 handled;
|
||||||
|
|
||||||
/* device */
|
GstOssCommon common;
|
||||||
gchar *device;
|
|
||||||
|
|
||||||
/* soundcard state */
|
|
||||||
int fd;
|
|
||||||
int caps; /* the capabilities */
|
|
||||||
gint format;
|
|
||||||
gint width;
|
|
||||||
gint channels;
|
|
||||||
gint frequency;
|
|
||||||
gint fragment;
|
|
||||||
gint fragment_size;
|
|
||||||
gboolean mute;
|
gboolean mute;
|
||||||
guint bufsize;
|
guint bufsize;
|
||||||
guint bps;
|
|
||||||
|
|
||||||
guint64 fragment_time;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstOssSinkClass {
|
struct _GstOssSinkClass {
|
||||||
|
@ -97,9 +82,6 @@ GType gst_osssink_get_type(void);
|
||||||
|
|
||||||
gboolean gst_osssink_factory_init(GstPlugin *plugin);
|
gboolean gst_osssink_factory_init(GstPlugin *plugin);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
G_END_DECLS
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GST_OSSSINK_H__ */
|
#endif /* __GST_OSSSINK_H__ */
|
||||||
|
|
|
@ -51,7 +51,8 @@ enum {
|
||||||
enum {
|
enum {
|
||||||
ARG_0,
|
ARG_0,
|
||||||
ARG_DEVICE,
|
ARG_DEVICE,
|
||||||
ARG_BYTESPERREAD,
|
ARG_BUFFERSIZE,
|
||||||
|
ARG_FRAGMENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
GST_PAD_TEMPLATE_FACTORY (osssrc_src_factory,
|
GST_PAD_TEMPLATE_FACTORY (osssrc_src_factory,
|
||||||
|
@ -85,16 +86,23 @@ static void gst_osssrc_class_init (GstOssSrcClass *klass);
|
||||||
static void gst_osssrc_init (GstOssSrc *osssrc);
|
static void gst_osssrc_init (GstOssSrc *osssrc);
|
||||||
|
|
||||||
static GstPadConnectReturn gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps);
|
static GstPadConnectReturn gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps);
|
||||||
|
static const GstFormat* gst_osssrc_get_formats (GstPad *pad);
|
||||||
|
static gboolean gst_osssrc_convert (GstPad *pad,
|
||||||
|
GstFormat src_format, gint64 src_value,
|
||||||
|
GstFormat *dest_format, gint64 *dest_value);
|
||||||
|
|
||||||
static void gst_osssrc_set_property (GObject *object, guint prop_id,
|
static void gst_osssrc_set_property (GObject *object, guint prop_id,
|
||||||
const GValue *value, GParamSpec *pspec);
|
const GValue *value, GParamSpec *pspec);
|
||||||
static void gst_osssrc_get_property (GObject *object, guint prop_id,
|
static void gst_osssrc_get_property (GObject *object, guint prop_id,
|
||||||
GValue *value, GParamSpec *pspec);
|
GValue *value, GParamSpec *pspec);
|
||||||
static GstElementStateReturn gst_osssrc_change_state (GstElement *element);
|
static GstElementStateReturn gst_osssrc_change_state (GstElement *element);
|
||||||
|
|
||||||
static gboolean gst_osssrc_send_event (GstElement *element, GstEvent *event);
|
static const GstEventMask* gst_osssrc_get_event_masks (GstPad *pad);
|
||||||
static void gst_osssrc_close_audio (GstOssSrc *src);
|
static gboolean gst_osssrc_src_event (GstPad *pad, GstEvent *event);
|
||||||
static gboolean gst_osssrc_open_audio (GstOssSrc *src);
|
static gboolean gst_osssrc_send_event (GstElement *element, GstEvent *event);
|
||||||
static gboolean gst_osssrc_sync_parms (GstOssSrc *osssrc);
|
static const GstPadQueryType* gst_osssrc_get_query_types (GstPad *pad);
|
||||||
|
static gboolean gst_osssrc_src_query (GstPad *pad, GstPadQueryType type,
|
||||||
|
GstFormat *format, gint64 *value);
|
||||||
|
|
||||||
static GstBuffer * gst_osssrc_get (GstPad *pad);
|
static GstBuffer * gst_osssrc_get (GstPad *pad);
|
||||||
|
|
||||||
|
@ -134,12 +142,16 @@ gst_osssrc_class_init (GstOssSrcClass *klass)
|
||||||
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||||
|
|
||||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BYTESPERREAD,
|
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFFERSIZE,
|
||||||
g_param_spec_ulong("bytes_per_read","bytes_per_read","bytes_per_read",
|
g_param_spec_ulong ("buffersize","Buffer Size","The size of the buffers with samples",
|
||||||
0,G_MAXULONG,0,G_PARAM_READWRITE)); /* CHECKME */
|
0, G_MAXULONG, 0, G_PARAM_READWRITE));
|
||||||
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
|
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
|
||||||
g_param_spec_string("device","device","oss device (/dev/dspN usually)",
|
g_param_spec_string ("device", "device", "oss device (/dev/dspN usually)",
|
||||||
"default",G_PARAM_READWRITE));
|
"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)",
|
||||||
|
0, G_MAXINT, 6, G_PARAM_READWRITE));
|
||||||
|
|
||||||
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;
|
||||||
|
@ -155,25 +167,20 @@ gst_osssrc_init (GstOssSrc *osssrc)
|
||||||
GST_PAD_TEMPLATE_GET (osssrc_src_factory), "src");
|
GST_PAD_TEMPLATE_GET (osssrc_src_factory), "src");
|
||||||
gst_pad_set_get_function (osssrc->srcpad, gst_osssrc_get);
|
gst_pad_set_get_function (osssrc->srcpad, gst_osssrc_get);
|
||||||
gst_pad_set_connect_function (osssrc->srcpad, gst_osssrc_srcconnect);
|
gst_pad_set_connect_function (osssrc->srcpad, gst_osssrc_srcconnect);
|
||||||
|
gst_pad_set_convert_function (osssrc->srcpad, gst_osssrc_convert);
|
||||||
|
gst_pad_set_formats_function (osssrc->srcpad, gst_osssrc_get_formats);
|
||||||
|
gst_pad_set_event_function (osssrc->srcpad, gst_osssrc_src_event);
|
||||||
|
gst_pad_set_event_mask_function (osssrc->srcpad, gst_osssrc_get_event_masks);
|
||||||
|
gst_pad_set_query_function (osssrc->srcpad, gst_osssrc_src_query);
|
||||||
|
gst_pad_set_query_type_function (osssrc->srcpad, gst_osssrc_get_query_types);
|
||||||
|
|
||||||
|
|
||||||
gst_element_add_pad (GST_ELEMENT (osssrc), osssrc->srcpad);
|
gst_element_add_pad (GST_ELEMENT (osssrc), osssrc->srcpad);
|
||||||
|
|
||||||
osssrc->device = g_strdup ("/dev/dsp");
|
gst_osscommon_init (&osssrc->common);
|
||||||
osssrc->fd = -1;
|
|
||||||
|
|
||||||
/* adding some default values */
|
osssrc->buffersize = 4096;
|
||||||
osssrc->law = 0;
|
|
||||||
osssrc->endianness = G_BYTE_ORDER;
|
|
||||||
osssrc->sign = TRUE;
|
|
||||||
osssrc->depth = 16;
|
|
||||||
osssrc->width = 16;
|
|
||||||
osssrc->channels = 2;
|
|
||||||
osssrc->rate = 44100;
|
|
||||||
osssrc->need_eos = FALSE;
|
|
||||||
|
|
||||||
osssrc->bytes_per_read = 4096;
|
|
||||||
osssrc->curoffset = 0;
|
osssrc->curoffset = 0;
|
||||||
osssrc->basetime = 0;
|
|
||||||
osssrc->samples_since_basetime = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstPadConnectReturn
|
static GstPadConnectReturn
|
||||||
|
@ -186,29 +193,14 @@ gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps)
|
||||||
if (!GST_CAPS_IS_FIXED (caps))
|
if (!GST_CAPS_IS_FIXED (caps))
|
||||||
return GST_PAD_CONNECT_DELAYED;
|
return GST_PAD_CONNECT_DELAYED;
|
||||||
|
|
||||||
gst_caps_get_int (caps, "law", &src->law);
|
if (!gst_osscommon_parse_caps (&src->common, caps))
|
||||||
gst_caps_get_int (caps, "endianness", &src->endianness);
|
return GST_PAD_CONNECT_REFUSED;
|
||||||
gst_caps_get_boolean (caps, "signed", &src->sign);
|
|
||||||
gst_caps_get_int (caps, "width", &src->width);
|
|
||||||
gst_caps_get_int (caps, "depth", &src->depth);
|
|
||||||
gst_caps_get_int (caps, "rate", &src->rate);
|
|
||||||
gst_caps_get_int (caps, "channels", &src->channels);
|
|
||||||
|
|
||||||
if (!gst_osssrc_sync_parms (src))
|
if (!gst_osscommon_sync_parms (&src->common))
|
||||||
return GST_PAD_CONNECT_REFUSED;
|
return GST_PAD_CONNECT_REFUSED;
|
||||||
|
|
||||||
return GST_PAD_CONNECT_OK;
|
return GST_PAD_CONNECT_OK;
|
||||||
}
|
}
|
||||||
#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
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_osssrc_negotiate (GstPad *pad)
|
gst_osssrc_negotiate (GstPad *pad)
|
||||||
|
@ -220,16 +212,10 @@ gst_osssrc_negotiate (GstPad *pad)
|
||||||
|
|
||||||
allowed = gst_pad_get_allowed_caps (pad);
|
allowed = gst_pad_get_allowed_caps (pad);
|
||||||
|
|
||||||
/* peel off fixed stuff from the allowed caps */
|
if (!gst_osscommon_merge_fixed_caps (&src->common, allowed))
|
||||||
GET_FIXED_INT (allowed, "law", &src->law);
|
return FALSE;
|
||||||
GET_FIXED_INT (allowed, "endianness", &src->endianness);
|
|
||||||
GET_FIXED_BOOLEAN (allowed, "signed", &src->sign);
|
|
||||||
GET_FIXED_INT (allowed, "width", &src->width);
|
|
||||||
GET_FIXED_INT (allowed, "depth", &src->depth);
|
|
||||||
GET_FIXED_INT (allowed, "rate", &src->rate);
|
|
||||||
GET_FIXED_INT (allowed, "channels", &src->channels);
|
|
||||||
|
|
||||||
if (!gst_osssrc_sync_parms (src))
|
if (!gst_osscommon_sync_parms (&src->common))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* set caps on src pad */
|
/* set caps on src pad */
|
||||||
|
@ -238,13 +224,13 @@ gst_osssrc_negotiate (GstPad *pad)
|
||||||
"oss_src",
|
"oss_src",
|
||||||
"audio/raw",
|
"audio/raw",
|
||||||
"format", GST_PROPS_STRING ("int"),
|
"format", GST_PROPS_STRING ("int"),
|
||||||
"law", GST_PROPS_INT (src->law),
|
"law", GST_PROPS_INT (src->common.law),
|
||||||
"endianness", GST_PROPS_INT (src->endianness),
|
"endianness", GST_PROPS_INT (src->common.endianness),
|
||||||
"signed", GST_PROPS_BOOLEAN (src->sign),
|
"signed", GST_PROPS_BOOLEAN (src->common.sign),
|
||||||
"width", GST_PROPS_INT (src->width),
|
"width", GST_PROPS_INT (src->common.width),
|
||||||
"depth", GST_PROPS_INT (src->depth),
|
"depth", GST_PROPS_INT (src->common.depth),
|
||||||
"rate", GST_PROPS_INT (src->rate),
|
"rate", GST_PROPS_INT (src->common.rate),
|
||||||
"channels", GST_PROPS_INT (src->channels)
|
"channels", GST_PROPS_INT (src->common.channels)
|
||||||
)) <= 0)
|
)) <= 0)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -258,7 +244,6 @@ gst_osssrc_get (GstPad *pad)
|
||||||
GstOssSrc *src;
|
GstOssSrc *src;
|
||||||
GstBuffer *buf;
|
GstBuffer *buf;
|
||||||
glong readbytes;
|
glong readbytes;
|
||||||
glong readsamples;
|
|
||||||
|
|
||||||
src = GST_OSSSRC(gst_pad_get_parent (pad));
|
src = GST_OSSSRC(gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
@ -269,10 +254,10 @@ gst_osssrc_get (GstPad *pad)
|
||||||
return GST_BUFFER (gst_event_new (GST_EVENT_EOS));
|
return GST_BUFFER (gst_event_new (GST_EVENT_EOS));
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = gst_buffer_new_and_alloc (src->bytes_per_read);
|
buf = gst_buffer_new_and_alloc (src->buffersize);
|
||||||
|
|
||||||
readbytes = read (src->fd,GST_BUFFER_DATA (buf),
|
readbytes = read (src->common.fd,GST_BUFFER_DATA (buf),
|
||||||
src->bytes_per_read);
|
src->buffersize);
|
||||||
|
|
||||||
if (readbytes == 0) {
|
if (readbytes == 0) {
|
||||||
gst_element_set_eos (GST_ELEMENT (src));
|
gst_element_set_eos (GST_ELEMENT (src));
|
||||||
|
@ -286,16 +271,16 @@ gst_osssrc_get (GstPad *pad)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (src->common.bps == 0) {
|
||||||
|
gst_element_error (GST_ELEMENT (src), "no format negotiated");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
GST_BUFFER_SIZE (buf) = readbytes;
|
GST_BUFFER_SIZE (buf) = readbytes;
|
||||||
GST_BUFFER_OFFSET (buf) = src->curoffset;
|
GST_BUFFER_OFFSET (buf) = src->curoffset;
|
||||||
GST_BUFFER_TIMESTAMP (buf) = src->basetime +
|
GST_BUFFER_TIMESTAMP (buf) = src->curoffset * GST_SECOND / src->common.bps;
|
||||||
src->samples_since_basetime * GST_SECOND / src->rate;
|
|
||||||
|
|
||||||
src->curoffset += readbytes;
|
src->curoffset += readbytes;
|
||||||
readsamples = readbytes / src->channels;
|
|
||||||
if (src->width == 16) readsamples /= 2;
|
|
||||||
src->samples_since_basetime += readsamples;
|
|
||||||
|
|
||||||
GST_DEBUG (GST_CAT_PLUGIN_INFO, "pushed buffer from soundcard of %ld bytes, timestamp %lld",
|
GST_DEBUG (GST_CAT_PLUGIN_INFO, "pushed buffer from soundcard of %ld bytes, timestamp %lld",
|
||||||
readbytes, GST_BUFFER_TIMESTAMP (buf));
|
readbytes, GST_BUFFER_TIMESTAMP (buf));
|
||||||
|
@ -308,19 +293,20 @@ gst_osssrc_set_property (GObject *object, guint prop_id, const GValue *value, GP
|
||||||
{
|
{
|
||||||
GstOssSrc *src;
|
GstOssSrc *src;
|
||||||
|
|
||||||
/* it's not null if we got it, but it might not be ours */
|
|
||||||
g_return_if_fail (GST_IS_OSSSRC (object));
|
|
||||||
|
|
||||||
src = GST_OSSSRC (object);
|
src = GST_OSSSRC (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_BYTESPERREAD:
|
case ARG_BUFFERSIZE:
|
||||||
src->bytes_per_read = g_value_get_ulong (value);
|
src->buffersize = g_value_get_ulong (value);
|
||||||
break;
|
break;
|
||||||
case ARG_DEVICE:
|
case ARG_DEVICE:
|
||||||
g_free(src->device);
|
g_free(src->common.device);
|
||||||
src->device = g_strdup (g_value_get_string (value));
|
src->common.device = g_strdup (g_value_get_string (value));
|
||||||
break;
|
break;
|
||||||
|
case ARG_FRAGMENT:
|
||||||
|
src->common.fragment = g_value_get_int (value);
|
||||||
|
gst_osscommon_sync_parms (&src->common);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -331,17 +317,17 @@ gst_osssrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSp
|
||||||
{
|
{
|
||||||
GstOssSrc *src;
|
GstOssSrc *src;
|
||||||
|
|
||||||
/* it's not null if we got it, but it might not be ours */
|
|
||||||
g_return_if_fail (GST_IS_OSSSRC (object));
|
|
||||||
|
|
||||||
src = GST_OSSSRC (object);
|
src = GST_OSSSRC (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case ARG_BYTESPERREAD:
|
case ARG_BUFFERSIZE:
|
||||||
g_value_set_ulong (value, src->bytes_per_read);
|
g_value_set_ulong (value, src->buffersize);
|
||||||
break;
|
break;
|
||||||
case ARG_DEVICE:
|
case ARG_DEVICE:
|
||||||
g_value_set_string (value, src->device);
|
g_value_set_string (value, src->common.device);
|
||||||
|
break;
|
||||||
|
case ARG_FRAGMENT:
|
||||||
|
g_value_set_int (value, src->common.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);
|
||||||
|
@ -361,8 +347,13 @@ gst_osssrc_change_state (GstElement *element)
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_PAUSED:
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
if (!GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) {
|
if (!GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) {
|
||||||
if (!gst_osssrc_open_audio (osssrc))
|
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;
|
return GST_STATE_FAILURE;
|
||||||
|
}
|
||||||
|
GST_FLAG_SET (osssrc, GST_OSSSRC_OPEN);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case GST_STATE_PAUSED_TO_PLAYING:
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
|
@ -370,8 +361,11 @@ gst_osssrc_change_state (GstElement *element)
|
||||||
case GST_STATE_PLAYING_TO_PAUSED:
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
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)) {
|
||||||
gst_osssrc_close_audio (osssrc);
|
gst_osscommon_close_audio (&osssrc->common);
|
||||||
|
GST_FLAG_UNSET (osssrc, GST_OSSSRC_OPEN);
|
||||||
|
}
|
||||||
|
gst_osscommon_init (&osssrc->common);
|
||||||
break;
|
break;
|
||||||
case GST_STATE_READY_TO_NULL:
|
case GST_STATE_READY_TO_NULL:
|
||||||
break;
|
break;
|
||||||
|
@ -383,103 +377,117 @@ gst_osssrc_change_state (GstElement *element)
|
||||||
return GST_STATE_SUCCESS;
|
return GST_STATE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static const GstFormat*
|
||||||
gst_osssrc_send_event (GstElement *element,
|
gst_osssrc_get_formats (GstPad *pad)
|
||||||
GstEvent *event)
|
{
|
||||||
|
static const GstFormat formats[] = {
|
||||||
|
GST_FORMAT_TIME,
|
||||||
|
GST_FORMAT_UNITS,
|
||||||
|
GST_FORMAT_BYTES,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
return formats;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_osssrc_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
|
||||||
|
GstFormat *dest_format, gint64 *dest_value)
|
||||||
{
|
{
|
||||||
gboolean retval = FALSE;
|
|
||||||
GstOssSrc *osssrc;
|
GstOssSrc *osssrc;
|
||||||
|
|
||||||
osssrc = GST_OSSSRC (element);
|
osssrc = GST_OSSSRC (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
return gst_osscommon_convert (&osssrc->common, src_format, src_value,
|
||||||
|
dest_format, dest_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const GstEventMask*
|
||||||
|
gst_osssrc_get_event_masks (GstPad *pad)
|
||||||
|
{
|
||||||
|
static const GstEventMask gst_osssrc_src_event_masks[] = {
|
||||||
|
{ GST_EVENT_EOS, 0 },
|
||||||
|
{ GST_EVENT_SIZE, 0 },
|
||||||
|
{ 0, }
|
||||||
|
};
|
||||||
|
return gst_osssrc_src_event_masks;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_osssrc_src_event (GstPad *pad, GstEvent *event)
|
||||||
|
{
|
||||||
|
GstOssSrc *osssrc;
|
||||||
|
gboolean retval = FALSE;
|
||||||
|
|
||||||
|
osssrc = GST_OSSSRC (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
switch (GST_EVENT_TYPE (event)) {
|
||||||
case GST_EVENT_EOS:
|
case GST_EVENT_EOS:
|
||||||
osssrc->need_eos = TRUE;
|
osssrc->need_eos = TRUE;
|
||||||
retval = TRUE;
|
retval = TRUE;
|
||||||
break;
|
break;
|
||||||
|
case GST_EVENT_SIZE:
|
||||||
|
{
|
||||||
|
GstFormat format;
|
||||||
|
gint64 value;
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
osssrc->buffersize = GST_EVENT_SIZE_VALUE (event);
|
||||||
|
g_object_notify (G_OBJECT (osssrc), "buffersize");
|
||||||
|
retval = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_event_unref (event);
|
gst_event_unref (event);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_osssrc_open_audio (GstOssSrc *src)
|
gst_osssrc_send_event (GstElement *element,
|
||||||
|
GstEvent *event)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_OSSSRC_OPEN), FALSE);
|
GstOssSrc *osssrc = GST_OSSSRC (element);
|
||||||
|
|
||||||
/* first try to open the sound card */
|
return gst_osssrc_src_event (osssrc->srcpad, event);
|
||||||
src->fd = open(src->device, O_RDONLY);
|
}
|
||||||
|
|
||||||
/* if we have it, set the default parameters and go have fun */
|
static const GstPadQueryType*
|
||||||
if (src->fd > 0) {
|
gst_osssrc_get_query_types (GstPad *pad)
|
||||||
|
{
|
||||||
|
static const GstPadQueryType query_types[] = {
|
||||||
|
GST_PAD_QUERY_POSITION,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
return query_types;
|
||||||
|
}
|
||||||
|
|
||||||
/* set card state */
|
static gboolean
|
||||||
GST_DEBUG (GST_CAT_PLUGIN_INFO,"opened audio: %s",src->device);
|
gst_osssrc_src_query (GstPad *pad, GstPadQueryType type, GstFormat *format, gint64 *value)
|
||||||
|
{
|
||||||
GST_FLAG_SET (src, GST_OSSSRC_OPEN);
|
gboolean res = FALSE;
|
||||||
return TRUE;
|
GstOssSrc *osssrc;
|
||||||
|
|
||||||
|
osssrc = GST_OSSSRC (gst_pad_get_parent (pad));
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case GST_PAD_QUERY_POSITION:
|
||||||
|
res = gst_osscommon_convert (&osssrc->common,
|
||||||
|
GST_FORMAT_BYTES, osssrc->curoffset,
|
||||||
|
format, value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
return FALSE;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_osssrc_close_audio (GstOssSrc *src)
|
|
||||||
{
|
|
||||||
g_return_if_fail (GST_FLAG_IS_SET (src, GST_OSSSRC_OPEN));
|
|
||||||
|
|
||||||
close(src->fd);
|
|
||||||
src->fd = -1;
|
|
||||||
|
|
||||||
GST_FLAG_UNSET (src, GST_OSSSRC_OPEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_osssrc_sync_parms (GstOssSrc *osssrc)
|
|
||||||
{
|
|
||||||
audio_buf_info ispace;
|
|
||||||
gint frag;
|
|
||||||
/* remember : ioctl on samplerate returns the sample rate the card
|
|
||||||
* is actually set to ! Setting it to 44101 Hz could cause it to
|
|
||||||
* be set to 44101, for example
|
|
||||||
*/
|
|
||||||
guint rate;
|
|
||||||
gint format;
|
|
||||||
gint bps;
|
|
||||||
|
|
||||||
g_return_val_if_fail (osssrc->fd > 0, FALSE);
|
|
||||||
|
|
||||||
/* get rate, we don't modify the original rate as the audio device
|
|
||||||
* might not exactly give us the requested value */
|
|
||||||
rate = osssrc->rate;
|
|
||||||
|
|
||||||
/* transform format parameters to oss format */
|
|
||||||
if (!gst_ossformat_get (osssrc->law, osssrc->endianness, osssrc->sign,
|
|
||||||
osssrc->width, osssrc->depth, &format, &bps))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
frag = 0x7fff0006;
|
|
||||||
|
|
||||||
ioctl(osssrc->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
|
|
||||||
ioctl(osssrc->fd, SNDCTL_DSP_RESET, 0);
|
|
||||||
|
|
||||||
ioctl(osssrc->fd, SNDCTL_DSP_SETFMT, &format);
|
|
||||||
ioctl(osssrc->fd, SNDCTL_DSP_CHANNELS, &osssrc->channels);
|
|
||||||
ioctl(osssrc->fd, SNDCTL_DSP_SPEED, &rate);
|
|
||||||
ioctl(osssrc->fd, SNDCTL_DSP_GETISPACE, &ispace);
|
|
||||||
ioctl(osssrc->fd, SNDCTL_DSP_GETBLKSIZE, &frag);
|
|
||||||
|
|
||||||
g_print("setting sound card to %dHz %d bit %s (%d bytes buffer, %d fragment)\n",
|
|
||||||
rate, osssrc->width,
|
|
||||||
(osssrc->channels == 2) ? "stereo" : "mono", ispace.bytes, frag);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
gst_osssrc_factory_init (GstPlugin *plugin)
|
gst_osssrc_factory_init (GstPlugin *plugin)
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
#define __GST_OSSSRC_H__
|
#define __GST_OSSSRC_H__
|
||||||
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <gst/gst.h>
|
#include <gst/gst.h>
|
||||||
|
#include "gstosscommon.h"
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -51,34 +51,18 @@ typedef struct _GstOssSrc GstOssSrc;
|
||||||
typedef struct _GstOssSrcClass GstOssSrcClass;
|
typedef struct _GstOssSrcClass GstOssSrcClass;
|
||||||
|
|
||||||
struct _GstOssSrc {
|
struct _GstOssSrc {
|
||||||
GstElement element;
|
GstElement element;
|
||||||
|
|
||||||
/* pads */
|
/* pads */
|
||||||
GstPad *srcpad;
|
GstPad *srcpad;
|
||||||
|
|
||||||
/* device */
|
GstOssCommon common;
|
||||||
gchar *device;
|
|
||||||
|
|
||||||
/* sound card */
|
gboolean need_eos; /* Do we need to emit an EOS? */
|
||||||
gint fd;
|
|
||||||
|
|
||||||
/* audio parameters */
|
|
||||||
gint law;
|
|
||||||
gint endianness;
|
|
||||||
gint sign;
|
|
||||||
gint width;
|
|
||||||
gint depth;
|
|
||||||
gint rate;
|
|
||||||
gint channels;
|
|
||||||
|
|
||||||
gboolean need_eos; /* Do we need to emit an EOS? */
|
|
||||||
|
|
||||||
/* blocking */
|
/* blocking */
|
||||||
guint64 basetime;
|
gulong curoffset;
|
||||||
guint64 samples_since_basetime;
|
gulong buffersize;
|
||||||
gulong curoffset;
|
|
||||||
gulong bytes_per_read;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstOssSrcClass {
|
struct _GstOssSrcClass {
|
||||||
|
|
Loading…
Reference in a new issue