1 /* GStreamer OSS Mixer implementation
2 * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
4 * gstossmixer.c: mixer interface implementation for OSS
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
32 #include <sys/ioctl.h>
34 #ifdef HAVE_OSS_INCLUDE_IN_SYS
35 # include <sys/soundcard.h>
37 # ifdef HAVE_OSS_INCLUDE_IN_ROOT
38 # include <soundcard.h>
40 # ifdef HAVE_OSS_INCLUDE_IN_MACHINE
41 # include <machine/soundcard.h>
43 # error "What to include?"
44 # endif /* HAVE_OSS_INCLUDE_IN_MACHINE */
45 # endif /* HAVE_OSS_INCLUDE_IN_ROOT */
46 #endif /* HAVE_OSS_INCLUDE_IN_SYS */
48 #include <gst/gst-i18n-plugin.h>
50 #include "gstossmixer.h"
51 #include "gstossmixertrack.h"
53 GST_DEBUG_CATEGORY_EXTERN (oss_debug);
54 #define GST_CAT_DEFAULT oss_debug
56 #define MASK_BIT_IS_SET(mask, bit) \
60 gst_ossmixer_open (GstOssMixer * mixer)
62 #ifdef SOUND_MIXER_INFO
63 struct mixer_info minfo;
66 g_return_val_if_fail (mixer->mixer_fd == -1, FALSE);
68 mixer->mixer_fd = open (mixer->device, O_RDWR);
69 if (mixer->mixer_fd == -1)
73 if (ioctl (mixer->mixer_fd, SOUND_MIXER_READ_RECMASK, &mixer->recmask) < 0
74 || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_RECSRC, &mixer->recdevs) < 0
75 || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_STEREODEVS,
76 &mixer->stereomask) < 0
77 || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_DEVMASK, &mixer->devmask) < 0
78 || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_CAPS, &mixer->mixcaps) < 0)
81 /* get name, not fatal */
82 g_free (mixer->cardname);
83 #ifdef SOUND_MIXER_INFO
84 if (ioctl (mixer->mixer_fd, SOUND_MIXER_INFO, &minfo) == 0) {
85 mixer->cardname = g_strdup (minfo.name);
86 GST_INFO ("Card name = %s", GST_STR_NULL (mixer->cardname));
90 mixer->cardname = g_strdup ("Unknown");
91 GST_INFO ("Unknown card name");
93 GST_INFO ("Opened mixer for device %s", mixer->device);
100 /* this is valid. OSS devices don't need to expose a mixer */
101 GST_DEBUG ("Failed to open mixer device %s, mixing disabled: %s",
102 mixer->device, strerror (errno));
107 GST_DEBUG ("Failed to get device masks");
108 close (mixer->mixer_fd);
109 mixer->mixer_fd = -1;
115 gst_ossmixer_ensure_track_list (GstOssMixer * mixer)
119 g_return_if_fail (mixer->mixer_fd != -1);
121 if (mixer->tracklist)
124 /* find master volume */
125 if (mixer->devmask & SOUND_MASK_VOLUME)
126 master = SOUND_MIXER_VOLUME;
127 else if (mixer->devmask & SOUND_MASK_PCM)
128 master = SOUND_MIXER_PCM;
129 else if (mixer->devmask & SOUND_MASK_SPEAKER)
130 master = SOUND_MIXER_SPEAKER; /* doubtful... */
131 /* else: no master, so we won't set any */
133 /* build track list */
134 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
135 if (mixer->devmask & (1 << i)) {
136 GstMixerTrack *track;
137 gboolean input = FALSE, stereo = FALSE, record = FALSE;
139 /* track exists, make up capabilities */
140 if (MASK_BIT_IS_SET (mixer->stereomask, i))
142 if (MASK_BIT_IS_SET (mixer->recmask, i))
144 if (MASK_BIT_IS_SET (mixer->recdevs, i))
147 /* do we want this in our list? */
148 if (!((mixer->dir & GST_OSS_MIXER_CAPTURE && input == TRUE) ||
149 (mixer->dir & GST_OSS_MIXER_PLAYBACK && i != SOUND_MIXER_PCM)))
150 /* the PLAYBACK case seems hacky, but that's how 0.8 had it */
153 /* add track to list */
154 track = gst_ossmixer_track_new (mixer->mixer_fd, i, stereo ? 2 : 1,
155 (record ? GST_MIXER_TRACK_RECORD : 0) |
156 (input ? GST_MIXER_TRACK_INPUT :
157 GST_MIXER_TRACK_OUTPUT) |
158 ((master != i) ? 0 : GST_MIXER_TRACK_MASTER));
159 mixer->tracklist = g_list_append (mixer->tracklist, track);
165 gst_ossmixer_new (const char *device, GstOssMixerDirection dir)
167 GstOssMixer *ret = NULL;
169 g_return_val_if_fail (device != NULL, NULL);
171 ret = g_new0 (GstOssMixer, 1);
173 ret->device = g_strdup (device);
177 if (!gst_ossmixer_open (ret))
185 gst_ossmixer_free (ret);
191 gst_ossmixer_free (GstOssMixer * mixer)
193 g_return_if_fail (mixer != NULL);
196 g_free (mixer->device);
197 mixer->device = NULL;
200 if (mixer->cardname) {
201 g_free (mixer->cardname);
202 mixer->cardname = NULL;
205 if (mixer->tracklist) {
206 g_list_foreach (mixer->tracklist, (GFunc) g_object_unref, NULL);
207 g_list_free (mixer->tracklist);
208 mixer->tracklist = NULL;
211 if (mixer->mixer_fd != -1) {
212 close (mixer->mixer_fd);
213 mixer->mixer_fd = -1;
219 /* unused with G_DISABLE_* */
220 static G_GNUC_UNUSED gboolean
221 gst_ossmixer_contains_track (GstOssMixer * mixer, GstOssMixerTrack * osstrack)
225 for (item = mixer->tracklist; item != NULL; item = item->next)
226 if (item->data == osstrack)
233 gst_ossmixer_list_tracks (GstOssMixer * mixer)
235 gst_ossmixer_ensure_track_list (mixer);
237 return (const GList *) mixer->tracklist;
241 gst_ossmixer_get_volume (GstOssMixer * mixer,
242 GstMixerTrack * track, gint * volumes)
245 GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track);
247 g_return_if_fail (mixer->mixer_fd != -1);
248 g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack));
250 if (track->flags & GST_MIXER_TRACK_MUTE) {
251 volumes[0] = osstrack->lvol;
252 if (track->num_channels == 2) {
253 volumes[1] = osstrack->rvol;
257 if (ioctl (mixer->mixer_fd, MIXER_READ (osstrack->track_num), &volume) < 0) {
258 g_warning ("Error getting recording device (%d) volume: %s",
259 osstrack->track_num, strerror (errno));
263 osstrack->lvol = volumes[0] = (volume & 0xff);
264 if (track->num_channels == 2) {
265 osstrack->rvol = volumes[1] = ((volume >> 8) & 0xff);
271 gst_ossmixer_set_volume (GstOssMixer * mixer,
272 GstMixerTrack * track, gint * volumes)
275 GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track);
277 g_return_if_fail (mixer->mixer_fd != -1);
278 g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack));
280 /* prepare the value for ioctl() */
281 if (!(track->flags & GST_MIXER_TRACK_MUTE)) {
282 volume = (volumes[0] & 0xff);
283 if (track->num_channels == 2) {
284 volume |= ((volumes[1] & 0xff) << 8);
288 if (ioctl (mixer->mixer_fd, MIXER_WRITE (osstrack->track_num), &volume) < 0) {
289 g_warning ("Error setting recording device (%d) volume (0x%x): %s",
290 osstrack->track_num, volume, strerror (errno));
295 osstrack->lvol = volumes[0];
296 if (track->num_channels == 2) {
297 osstrack->rvol = volumes[1];
302 gst_ossmixer_set_mute (GstOssMixer * mixer, GstMixerTrack * track,
306 GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track);
308 g_return_if_fail (mixer->mixer_fd != -1);
309 g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack));
314 volume = (osstrack->lvol & 0xff);
315 if (MASK_BIT_IS_SET (mixer->stereomask, osstrack->track_num)) {
316 volume |= ((osstrack->rvol & 0xff) << 8);
320 if (ioctl (mixer->mixer_fd, MIXER_WRITE (osstrack->track_num), &volume) < 0) {
321 g_warning ("Error setting mixer recording device volume (0x%x): %s",
322 volume, strerror (errno));
327 track->flags |= GST_MIXER_TRACK_MUTE;
329 track->flags &= ~GST_MIXER_TRACK_MUTE;
334 gst_ossmixer_set_record (GstOssMixer * mixer,
335 GstMixerTrack * track, gboolean record)
337 GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track);
339 g_return_if_fail (mixer->mixer_fd != -1);
340 g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack));
342 /* if there's nothing to do... */
343 if ((record && GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD)) ||
344 (!record && !GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD)))
347 /* if we're exclusive, then we need to unset the current one(s) */
348 if (mixer->mixcaps & SOUND_CAP_EXCL_INPUT) {
351 for (track = mixer->tracklist; track != NULL; track = track->next) {
352 GstMixerTrack *turn = (GstMixerTrack *) track->data;
354 turn->flags &= ~GST_MIXER_TRACK_RECORD;
359 /* set new record bit, if needed */
361 mixer->recdevs |= (1 << osstrack->track_num);
363 mixer->recdevs &= ~(1 << osstrack->track_num);
366 /* set it to the device */
367 if (ioctl (mixer->mixer_fd, SOUND_MIXER_WRITE_RECSRC, &mixer->recdevs) < 0) {
368 g_warning ("Error setting mixer recording devices (0x%x): %s",
369 mixer->recdevs, strerror (errno));
374 track->flags |= GST_MIXER_TRACK_RECORD;
376 track->flags &= ~GST_MIXER_TRACK_RECORD;