Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.git] / sys / oss4 / oss4-mixer-enum.c
1 /* GStreamer OSS4 mixer enumeration control
2  * Copyright (C) 2007-2008 Tim-Philipp Müller <tim centricular net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /* An 'enum' in gnome-volume-control / GstMixer is represented by a
21  * GstMixerOptions object
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <gst/gst-i18n-plugin.h>
29
30 #define NO_LEGACY_MIXER
31 #include "oss4-mixer.h"
32 #include "oss4-mixer-enum.h"
33 #include "oss4-soundcard.h"
34
35 GST_DEBUG_CATEGORY_EXTERN (oss4mixer_debug);
36 #define GST_CAT_DEFAULT oss4mixer_debug
37
38 static GList *gst_oss4_mixer_enum_get_values (GstMixerOptions * options);
39
40 /* GstMixerTrack is a plain GObject, so let's just use the GLib macro here */
41 G_DEFINE_TYPE (GstOss4MixerEnum, gst_oss4_mixer_enum, GST_TYPE_MIXER_OPTIONS);
42
43 static void
44 gst_oss4_mixer_enum_init (GstOss4MixerEnum * e)
45 {
46   e->need_update = TRUE;
47 }
48
49 static void
50 gst_oss4_mixer_enum_dispose (GObject * obj)
51 {
52   GstMixerOptions *options = GST_MIXER_OPTIONS (obj);
53
54   /* our list is a flat list with constant strings, but the GstMixerOptions
55    * dispose will try to g_free the contained strings, so clean up the list
56    * before chaining up to GstMixerOptions */
57   g_list_free (options->values);
58   options->values = NULL;
59
60   G_OBJECT_CLASS (gst_oss4_mixer_enum_parent_class)->dispose (obj);
61 }
62
63 static void
64 gst_oss4_mixer_enum_class_init (GstOss4MixerEnumClass * klass)
65 {
66   GObjectClass *gobject_class = (GObjectClass *) klass;
67   GstMixerOptionsClass *mixeroptions_class = (GstMixerOptionsClass *) klass;
68
69   gobject_class->dispose = gst_oss4_mixer_enum_dispose;
70   mixeroptions_class->get_values = gst_oss4_mixer_enum_get_values;
71 }
72
73 static GList *
74 gst_oss4_mixer_enum_get_values_locked (GstMixerOptions * options)
75 {
76   GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM_CAST (options);
77   GList *oldlist, *list = NULL;
78   int i;
79
80   /* if current list of values is empty, update/re-check in any case */
81   if (!e->need_update && options->values != NULL)
82     return options->values;
83
84   GST_LOG_OBJECT (e, "updating available values for %s", e->mc->mixext.extname);
85
86   for (i = 0; i < e->mc->mixext.maxvalue; ++i) {
87     const gchar *s;
88
89     s = g_quark_to_string (e->mc->enum_vals[i]);
90     if (MIXEXT_ENUM_IS_AVAILABLE (e->mc->mixext, i)) {
91       GST_LOG_OBJECT (e, "option '%s' is available", s);
92       list = g_list_prepend (list, (gpointer) s);
93     } else {
94       GST_LOG_OBJECT (e, "option '%s' is currently not available", s);
95     }
96   }
97
98   list = g_list_reverse (list);
99
100   /* this is not thread-safe, but then the entire GstMixer API isn't really,
101    * since we return foo->list and not a copy and don't take any locks, so
102    * not much we can do here but pray; we're usually either called from _new()
103    * or from within _get_values() though, so it should be okay. We could use
104    * atomic ops here, but I'm not sure how much more that really buys us.*/
105   oldlist = options->values;    /* keep window small */
106   options->values = list;
107   g_list_free (oldlist);
108
109   e->need_update = FALSE;
110
111   return options->values;
112 }
113
114 static GList *
115 gst_oss4_mixer_enum_get_values (GstMixerOptions * options)
116 {
117   GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM (options);
118   GList *list;
119
120   /* we take the lock here mostly to serialise ioctls with the watch thread */
121   GST_OBJECT_LOCK (e->mixer);
122
123   list = gst_oss4_mixer_enum_get_values_locked (options);
124
125   GST_OBJECT_UNLOCK (e->mixer);
126
127   return list;
128 }
129
130 static const gchar *
131 gst_oss4_mixer_enum_get_current_value (GstOss4MixerEnum * e)
132 {
133   const gchar *cur_val = NULL;
134
135   if (e->mc->enum_vals != NULL && e->mc->last_val < e->mc->mixext.maxvalue) {
136     cur_val = g_quark_to_string (e->mc->enum_vals[e->mc->last_val]);
137   }
138
139   return cur_val;
140 }
141
142 static gboolean
143 gst_oss4_mixer_enum_update_current (GstOss4MixerEnum * e)
144 {
145   int cur = -1;
146
147   if (!gst_oss4_mixer_get_control_val (e->mixer, e->mc, &cur))
148     return FALSE;
149
150   if (cur < 0 || cur >= e->mc->mixext.maxvalue) {
151     GST_WARNING_OBJECT (e, "read value %d out of bounds [0-%d]", cur,
152         e->mc->mixext.maxvalue - 1);
153     e->mc->last_val = 0;
154     return FALSE;
155   }
156
157   return TRUE;
158 }
159
160 gboolean
161 gst_oss4_mixer_enum_set_option (GstOss4MixerEnum * e, const gchar * value)
162 {
163   GQuark q;
164   int i;
165
166   q = g_quark_try_string (value);
167   if (q == 0) {
168     GST_WARNING_OBJECT (e, "unknown option '%s'", value);
169     return FALSE;
170   }
171
172   for (i = 0; i < e->mc->mixext.maxvalue; ++i) {
173     if (q == e->mc->enum_vals[i])
174       break;
175   }
176
177   if (i >= e->mc->mixext.maxvalue) {
178     GST_WARNING_OBJECT (e, "option '%s' is not valid for this control", value);
179     return FALSE;
180   }
181
182   GST_LOG_OBJECT (e, "option '%s' = %d", value, i);
183
184   if (!MIXEXT_ENUM_IS_AVAILABLE (e->mc->mixext, i)) {
185     GST_WARNING_OBJECT (e, "option '%s' is not selectable currently", value);
186     return FALSE;
187   }
188
189   if (!gst_oss4_mixer_set_control_val (e->mixer, e->mc, i)) {
190     GST_WARNING_OBJECT (e, "could not set option '%s' (%d)", value, i);
191     return FALSE;
192   }
193
194   /* and re-read current value with sanity checks (or could just assign here) */
195   gst_oss4_mixer_enum_update_current (e);
196
197   return TRUE;
198 }
199
200 const gchar *
201 gst_oss4_mixer_enum_get_option (GstOss4MixerEnum * e)
202 {
203   const gchar *cur_str = NULL;
204
205   if (!gst_oss4_mixer_enum_update_current (e)) {
206     GST_WARNING_OBJECT (e, "failed to read current value");
207     return NULL;
208   }
209
210   cur_str = gst_oss4_mixer_enum_get_current_value (e);
211   GST_LOG_OBJECT (e, "%s (%d)", GST_STR_NULL (cur_str), e->mc->last_val);
212   return cur_str;
213 }
214
215 GstMixerTrack *
216 gst_oss4_mixer_enum_new (GstOss4Mixer * mixer, GstOss4MixerControl * mc)
217 {
218   GstOss4MixerEnum *e;
219   GstMixerTrack *track;
220
221   e = g_object_new (GST_TYPE_OSS4_MIXER_ENUM, "untranslated-label",
222       mc->mixext.extname, NULL);
223   e->mixer = mixer;
224   e->mc = mc;
225
226   track = GST_MIXER_TRACK (e);
227
228   /* caller will set track->label and track->flags */
229
230   track->num_channels = 0;
231   track->min_volume = 0;
232   track->max_volume = 0;
233
234   (void) gst_oss4_mixer_enum_get_values_locked (GST_MIXER_OPTIONS (track));
235
236   if (!gst_oss4_mixer_enum_update_current (e)) {
237     GST_WARNING_OBJECT (track, "failed to read current value, returning NULL");
238     g_object_unref (track);
239     track = NULL;
240   }
241
242   GST_LOG_OBJECT (e, "current value: %d (%s)", e->mc->last_val,
243       gst_oss4_mixer_enum_get_current_value (e));
244
245   return track;
246 }
247
248 /* This is called from the watch thread */
249 void
250 gst_oss4_mixer_enum_process_change_unlocked (GstMixerTrack * track)
251 {
252   GstOss4MixerEnum *e = GST_OSS4_MIXER_ENUM_CAST (track);
253
254   gchar *cur;
255
256   if (!e->mc->changed && !e->mc->list_changed)
257     return;
258
259   if (e->mc->list_changed) {
260     gst_mixer_options_list_changed (GST_MIXER (e->mixer),
261         GST_MIXER_OPTIONS (e));
262   }
263
264   GST_OBJECT_LOCK (e->mixer);
265   cur = (gchar *) gst_oss4_mixer_enum_get_current_value (e);
266   GST_OBJECT_UNLOCK (e->mixer);
267
268   gst_mixer_option_changed (GST_MIXER (e->mixer), GST_MIXER_OPTIONS (e), cur);
269 }