diff options
author | Daniel Willmann <d.willmann@samsung.com> | 2013-04-17 18:31:38 +0100 |
---|---|---|
committer | Daniel Willmann <d.willmann@samsung.com> | 2013-04-18 19:14:32 +0100 |
commit | 72556567385540aaf98cb9848fd5ecbff1bcad67 (patch) | |
tree | 106ca27e7cb53ba82a6d5ed9a3da44a345838669 /src/lib/ecore_audio | |
parent | 01e4c9597e344ce4e34f7889883452ae0dd0a928 (diff) |
ecore_audio: Add pulseaudio output for eo
Signed-off-by: Daniel Willmann <d.willmann@samsung.com>
Diffstat (limited to 'src/lib/ecore_audio')
-rw-r--r-- | src/lib/ecore_audio/Ecore_Audio.h | 2 | ||||
-rw-r--r-- | src/lib/ecore_audio/ecore_audio_obj_out_pulse.c | 271 | ||||
-rw-r--r-- | src/lib/ecore_audio/ecore_audio_obj_out_pulse.h | 57 | ||||
-rw-r--r-- | src/lib/ecore_audio/ecore_audio_private.h | 14 | ||||
-rw-r--r-- | src/lib/ecore_audio/ecore_audio_pulse_ml.c | 308 |
5 files changed, 638 insertions, 14 deletions
diff --git a/src/lib/ecore_audio/Ecore_Audio.h b/src/lib/ecore_audio/Ecore_Audio.h index 8a542176e1..b87f6479cc 100644 --- a/src/lib/ecore_audio/Ecore_Audio.h +++ b/src/lib/ecore_audio/Ecore_Audio.h | |||
@@ -576,4 +576,6 @@ EAPI void ecore_audio_input_callback_setup(Ecore_Audio_Object *in | |||
576 | 576 | ||
577 | #include <ecore_audio_obj_in_tone.h> | 577 | #include <ecore_audio_obj_in_tone.h> |
578 | 578 | ||
579 | #include <ecore_audio_obj_out_pulse.h> | ||
580 | |||
579 | #endif | 581 | #endif |
diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_pulse.c b/src/lib/ecore_audio/ecore_audio_obj_out_pulse.c new file mode 100644 index 0000000000..4a3f9f86b5 --- /dev/null +++ b/src/lib/ecore_audio/ecore_audio_obj_out_pulse.c | |||
@@ -0,0 +1,271 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #include <stdlib.h> | ||
6 | #include <stdio.h> | ||
7 | #include <string.h> | ||
8 | |||
9 | #ifdef HAVE_FEATURES_H | ||
10 | #include <features.h> | ||
11 | #endif | ||
12 | |||
13 | #include <Eo.h> | ||
14 | #include "ecore_audio_private.h" | ||
15 | #include <pulse/pulseaudio.h> | ||
16 | |||
17 | #include <sys/time.h> | ||
18 | #include <sys/types.h> | ||
19 | #include <sys/socket.h> | ||
20 | |||
21 | extern pa_mainloop_api functable; | ||
22 | |||
23 | EAPI Eo_Op ECORE_AUDIO_OBJ_OUT_PULSE_BASE_ID = EO_NOOP; | ||
24 | |||
25 | #define MY_CLASS ECORE_AUDIO_OBJ_OUT_PULSE_CLASS | ||
26 | #define MY_CLASS_NAME "ecore_audio_obj_out_pulse" | ||
27 | |||
28 | const Eo_Event_Description _ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY; | ||
29 | #define ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY (&(_ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY)) | ||
30 | |||
31 | struct _Ecore_Audio_Pulse_Class { | ||
32 | pa_mainloop_api *api; | ||
33 | pa_context *context; | ||
34 | pa_context_state_t state; | ||
35 | Eina_List *outputs; | ||
36 | }; | ||
37 | |||
38 | static struct _Ecore_Audio_Pulse_Class class_vars = { | ||
39 | .api = &functable, | ||
40 | }; | ||
41 | |||
42 | struct _Ecore_Audio_Pulse | ||
43 | { | ||
44 | char *foo; | ||
45 | }; | ||
46 | |||
47 | typedef struct _Ecore_Audio_Pulse Ecore_Audio_Pulse; | ||
48 | |||
49 | static void _volume_set(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list) | ||
50 | { | ||
51 | Eo *in; | ||
52 | pa_stream *stream; | ||
53 | Eina_List *input; | ||
54 | uint32_t idx; | ||
55 | pa_cvolume pa_volume; | ||
56 | Ecore_Audio_Output *out_obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_OUT_CLASS); | ||
57 | |||
58 | double volume = va_arg(*list, double); | ||
59 | |||
60 | if (volume < 0) | ||
61 | volume = 0; | ||
62 | |||
63 | pa_cvolume_set(&pa_volume, 2, volume * PA_VOLUME_NORM); | ||
64 | |||
65 | eo_do_super(eo_obj, MY_CLASS, ecore_audio_obj_volume_set(volume)); | ||
66 | |||
67 | EINA_LIST_FOREACH(out_obj->inputs, input, in) { | ||
68 | eo_do(in, eo_base_data_get("pulse_data", (void **)&stream)); | ||
69 | idx = pa_stream_get_index(stream); | ||
70 | pa_operation_unref(pa_context_set_sink_input_volume(class_vars.context, idx, &pa_volume, NULL, NULL)); | ||
71 | } | ||
72 | |||
73 | } | ||
74 | |||
75 | static void _write_cb(pa_stream *stream, size_t len, void *data) | ||
76 | { | ||
77 | Eo *in = data; | ||
78 | |||
79 | void *buf; | ||
80 | ssize_t bread; | ||
81 | |||
82 | buf = malloc(len); | ||
83 | |||
84 | eo_do(in, ecore_audio_obj_in_read(buf, len, &bread)); | ||
85 | pa_stream_write(stream, buf, bread, free, 0, PA_SEEK_RELATIVE); | ||
86 | if (bread < len) | ||
87 | { | ||
88 | //in->ended = EINA_TRUE; | ||
89 | pa_operation_unref(pa_stream_drain(stream, NULL, NULL)); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static Eina_Bool _update_samplerate_cb(void *data, Eo *eo_obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED) | ||
94 | { | ||
95 | Eo *out = data; | ||
96 | pa_stream *stream; | ||
97 | int samplerate; | ||
98 | double speed; | ||
99 | |||
100 | eo_do(eo_obj, ecore_audio_obj_in_samplerate_get(&samplerate)); | ||
101 | eo_do(eo_obj, ecore_audio_obj_in_speed_get(&speed)); | ||
102 | |||
103 | eo_do(eo_obj, eo_base_data_get("pulse_data", &stream)); | ||
104 | |||
105 | pa_operation_unref(pa_stream_update_sample_rate(stream, samplerate * speed, NULL, NULL)); | ||
106 | } | ||
107 | |||
108 | static void _input_attach_internal(Eo *eo_obj, Eo *in) | ||
109 | { | ||
110 | const char *name; | ||
111 | pa_sample_spec ss; | ||
112 | double speed; | ||
113 | pa_stream *stream; | ||
114 | Ecore_Audio_Object *ea_obj = eo_data_get(eo_obj, ECORE_AUDIO_OBJ_CLASS); | ||
115 | |||
116 | ss.format = PA_SAMPLE_FLOAT32LE; | ||
117 | eo_do(in, ecore_audio_obj_in_samplerate_get(&ss.rate)); | ||
118 | eo_do(in, ecore_audio_obj_in_speed_get(&speed)); | ||
119 | eo_do(in, ecore_audio_obj_in_channels_get(&ss.channels)); | ||
120 | eo_do(in, ecore_audio_obj_name_get(&name)); | ||
121 | |||
122 | ss.rate = ss.rate * speed; | ||
123 | |||
124 | stream = pa_stream_new(class_vars.context, name, &ss, NULL); | ||
125 | if (!stream) { | ||
126 | ERR("Could not create stream"); | ||
127 | return; | ||
128 | } | ||
129 | |||
130 | eo_do_super(eo_obj, MY_CLASS, ecore_audio_obj_out_input_attach(in)); | ||
131 | |||
132 | eo_do(in, eo_event_callback_add(ECORE_AUDIO_EV_IN_SAMPLERATE_CHANGED, _update_samplerate_cb, eo_obj)); | ||
133 | |||
134 | eo_do(in, eo_base_data_set("pulse_data", stream, NULL)); | ||
135 | |||
136 | //FIXME: Handle paused state | ||
137 | |||
138 | pa_stream_set_write_callback(stream, _write_cb, in); | ||
139 | pa_stream_connect_playback(stream, NULL, NULL, PA_STREAM_VARIABLE_RATE, NULL, NULL); | ||
140 | } | ||
141 | |||
142 | static Eina_Bool _delayed_attach_cb(void *data, Eo *eo_obj, const Eo_Event_Description *desc EINA_UNUSED, void *event_info EINA_UNUSED) | ||
143 | { | ||
144 | Eo *in = data; | ||
145 | eo_do(eo_obj, eo_event_callback_del(ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY, _delayed_attach_cb, in)); | ||
146 | |||
147 | _input_attach_internal(eo_obj, in); | ||
148 | |||
149 | return EINA_TRUE; | ||
150 | } | ||
151 | |||
152 | static void _input_attach(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list) | ||
153 | { | ||
154 | Eo *in = va_arg(*list, Eo *); | ||
155 | |||
156 | if (class_vars.state != PA_CONTEXT_READY) { | ||
157 | DBG("Delaying input_attach because PA context is not ready."); | ||
158 | eo_do(eo_obj, eo_event_callback_add(ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY, _delayed_attach_cb, in)); | ||
159 | } else { | ||
160 | _input_attach_internal(eo_obj, in); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static void _drain_cb(pa_stream *stream, int success EINA_UNUSED, void *data EINA_UNUSED) | ||
165 | { | ||
166 | pa_stream_disconnect(stream); | ||
167 | pa_stream_unref(stream); | ||
168 | } | ||
169 | |||
170 | static void _input_detach(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list) | ||
171 | { | ||
172 | pa_stream *stream; | ||
173 | |||
174 | Eo *in = va_arg(*list, Eo *); | ||
175 | |||
176 | eo_do(in, eo_base_data_get("pulse_data", (void **)&stream)); | ||
177 | |||
178 | pa_stream_set_write_callback(stream, NULL, NULL); | ||
179 | pa_operation_unref(pa_stream_drain(stream, _drain_cb, NULL)); | ||
180 | |||
181 | eo_do_super(eo_obj, MY_CLASS, ecore_audio_obj_out_input_detach(in)); | ||
182 | } | ||
183 | |||
184 | static void _state_cb(pa_context *context, void *data EINA_UNUSED) | ||
185 | { | ||
186 | Eina_List *out; | ||
187 | Eo *eo_obj; | ||
188 | pa_context_state_t state; | ||
189 | |||
190 | state = pa_context_get_state(context); | ||
191 | |||
192 | if (state == PA_CONTEXT_READY) { | ||
193 | DBG("PA context ready."); | ||
194 | EINA_LIST_FOREACH(class_vars.outputs, out, eo_obj) { | ||
195 | eo_do(eo_obj, eo_event_callback_call(ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY, NULL, NULL)); | ||
196 | } | ||
197 | } else { | ||
198 | DBG("Connection state %i", state); | ||
199 | } | ||
200 | |||
201 | class_vars.state = state; | ||
202 | } | ||
203 | |||
204 | static void _constructor(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) | ||
205 | { | ||
206 | int argc; | ||
207 | char **argv; | ||
208 | |||
209 | eo_do_super(eo_obj, MY_CLASS, eo_constructor()); | ||
210 | |||
211 | if (!class_vars.context) { | ||
212 | ecore_app_args_get(&argc, &argv); | ||
213 | if (!argc) { | ||
214 | DBG("Could not get program name, pulse outputs will be named ecore_audio"); | ||
215 | class_vars.context = pa_context_new(class_vars.api, "ecore_audio"); | ||
216 | } else { | ||
217 | class_vars.context = pa_context_new(class_vars.api, basename(argv[0])); | ||
218 | } | ||
219 | pa_context_set_state_callback(class_vars.context, _state_cb, NULL); | ||
220 | pa_context_connect(class_vars.context, NULL, PA_CONTEXT_NOFLAGS, NULL); | ||
221 | } | ||
222 | |||
223 | class_vars.outputs = eina_list_append(class_vars.outputs, eo_obj); | ||
224 | } | ||
225 | |||
226 | static void _destructor(Eo *eo_obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED) | ||
227 | { | ||
228 | eo_do_super(eo_obj, MY_CLASS, eo_destructor()); | ||
229 | |||
230 | class_vars.outputs = eina_list_remove(class_vars.outputs, eo_obj); | ||
231 | } | ||
232 | |||
233 | static void _class_constructor(Eo_Class *klass) | ||
234 | { | ||
235 | const Eo_Op_Func_Description func_desc[] = { | ||
236 | /* Virtual functions of parent class implemented in this class */ | ||
237 | EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor), | ||
238 | EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_DESTRUCTOR), _destructor), | ||
239 | |||
240 | EO_OP_FUNC(ECORE_AUDIO_OBJ_ID(ECORE_AUDIO_OBJ_SUB_ID_VOLUME_SET), _volume_set), | ||
241 | |||
242 | EO_OP_FUNC(ECORE_AUDIO_OBJ_OUT_ID(ECORE_AUDIO_OBJ_OUT_SUB_ID_INPUT_ATTACH), _input_attach), | ||
243 | EO_OP_FUNC(ECORE_AUDIO_OBJ_OUT_ID(ECORE_AUDIO_OBJ_OUT_SUB_ID_INPUT_DETACH), _input_detach), | ||
244 | EO_OP_FUNC_SENTINEL | ||
245 | }; | ||
246 | |||
247 | eo_class_funcs_set(klass, func_desc); | ||
248 | } | ||
249 | |||
250 | static const Eo_Op_Description op_desc[] = { | ||
251 | EO_OP_DESCRIPTION_SENTINEL | ||
252 | }; | ||
253 | |||
254 | static const Eo_Event_Description *event_desc[] = { | ||
255 | ECORE_AUDIO_EV_OUT_PULSE_CONTEXT_READY, | ||
256 | NULL | ||
257 | }; | ||
258 | |||
259 | |||
260 | static const Eo_Class_Description class_desc = { | ||
261 | EO_VERSION, | ||
262 | MY_CLASS_NAME, | ||
263 | EO_CLASS_TYPE_REGULAR, | ||
264 | EO_CLASS_DESCRIPTION_OPS(&ECORE_AUDIO_OBJ_OUT_PULSE_BASE_ID, op_desc, ECORE_AUDIO_OBJ_OUT_PULSE_SUB_ID_LAST), | ||
265 | event_desc, | ||
266 | sizeof(Ecore_Audio_Pulse), | ||
267 | _class_constructor, | ||
268 | NULL | ||
269 | }; | ||
270 | |||
271 | EO_DEFINE_CLASS(ecore_audio_obj_out_pulse_class_get, &class_desc, ECORE_AUDIO_OBJ_OUT_CLASS, NULL); | ||
diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_pulse.h b/src/lib/ecore_audio/ecore_audio_obj_out_pulse.h new file mode 100644 index 0000000000..f89413b8a4 --- /dev/null +++ b/src/lib/ecore_audio/ecore_audio_obj_out_pulse.h | |||
@@ -0,0 +1,57 @@ | |||
1 | #ifndef ECORE_AUDIO_OUT_PULSE_H | ||
2 | #define ECORE_AUDIO_OUT_PULSE_H | ||
3 | |||
4 | #include <Eina.h> | ||
5 | #include <Eo.h> | ||
6 | |||
7 | #ifdef EAPI | ||
8 | #undef EAPI | ||
9 | #endif | ||
10 | |||
11 | #ifdef __GNUC__ | ||
12 | #if __GNUC__ >= 4 | ||
13 | #define EAPI __attribute__ ((visibility("default"))) | ||
14 | #else | ||
15 | #define EAPI | ||
16 | #endif | ||
17 | #else | ||
18 | #define EAPI | ||
19 | #endif | ||
20 | |||
21 | /** | ||
22 | * @file ecore_audio_obj_out_pulse.h | ||
23 | * @brief Audio Module | ||
24 | */ | ||
25 | |||
26 | #ifdef __cplusplus | ||
27 | extern "C" | ||
28 | { | ||
29 | #endif | ||
30 | |||
31 | /** | ||
32 | * @addtogroup Ecore_Audio_Group | ||
33 | * @{ | ||
34 | */ | ||
35 | |||
36 | #define ECORE_AUDIO_OBJ_OUT_PULSE_CLASS ecore_audio_obj_out_pulse_class_get() | ||
37 | |||
38 | const Eo_Class *ecore_audio_obj_out_pulse_class_get() EINA_CONST; | ||
39 | |||
40 | extern EAPI Eo_Op ECORE_AUDIO_OBJ_OUT_PULSE_BASE_ID; | ||
41 | |||
42 | enum _Ecore_Audio_Obj_Out_Pulse_Sub_Ids | ||
43 | { | ||
44 | ECORE_AUDIO_OBJ_OUT_PULSE_SUB_ID_LAST | ||
45 | }; | ||
46 | |||
47 | #define ECORE_AUDIO_OBJ_OUT_PULSE_ID(sub_id) (ECORE_AUDIO_OBJ_OUT_PULSE_BASE_ID + EO_TYPECHECK(enum _Ecore_Audio_Obj_Out_Pulse_Sub_Ids, sub_id)) | ||
48 | |||
49 | /** | ||
50 | * @} | ||
51 | */ | ||
52 | |||
53 | #ifdef __cplusplus | ||
54 | } | ||
55 | #endif | ||
56 | |||
57 | #endif | ||
diff --git a/src/lib/ecore_audio/ecore_audio_private.h b/src/lib/ecore_audio/ecore_audio_private.h index ef08b74a9b..7868b08b5f 100644 --- a/src/lib/ecore_audio/ecore_audio_private.h +++ b/src/lib/ecore_audio/ecore_audio_private.h | |||
@@ -155,20 +155,6 @@ void ecore_audio_alsa_shutdown(void); | |||
155 | #endif /* HAVE_ALSA */ | 155 | #endif /* HAVE_ALSA */ |
156 | 156 | ||
157 | #ifdef HAVE_PULSE | 157 | #ifdef HAVE_PULSE |
158 | /* PA mainloop integration */ | ||
159 | struct _Ecore_Audio_Pa_Private | ||
160 | { | ||
161 | pa_mainloop_api api; | ||
162 | pa_context *context; | ||
163 | pa_context_state_t state; | ||
164 | }; | ||
165 | |||
166 | /* ecore_audio_pulse */ | ||
167 | struct _Ecore_Audio_Pulse | ||
168 | { | ||
169 | pa_stream *stream; | ||
170 | }; | ||
171 | |||
172 | Ecore_Audio_Module *ecore_audio_pulse_init(void); | 158 | Ecore_Audio_Module *ecore_audio_pulse_init(void); |
173 | void ecore_audio_pulse_shutdown(void); | 159 | void ecore_audio_pulse_shutdown(void); |
174 | #endif /* HAVE_PULSE */ | 160 | #endif /* HAVE_PULSE */ |
diff --git a/src/lib/ecore_audio/ecore_audio_pulse_ml.c b/src/lib/ecore_audio/ecore_audio_pulse_ml.c new file mode 100644 index 0000000000..67dd96b132 --- /dev/null +++ b/src/lib/ecore_audio/ecore_audio_pulse_ml.c | |||
@@ -0,0 +1,308 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | #include <config.h> | ||
3 | #endif | ||
4 | |||
5 | #include <stdlib.h> | ||
6 | #include <stdio.h> | ||
7 | #include <string.h> | ||
8 | |||
9 | #ifdef HAVE_FEATURES_H | ||
10 | #include <features.h> | ||
11 | #endif | ||
12 | #include <ctype.h> | ||
13 | #include <errno.h> | ||
14 | |||
15 | #include <pulse/pulseaudio.h> | ||
16 | |||
17 | #include <sys/time.h> | ||
18 | #include <sys/types.h> | ||
19 | #include <sys/socket.h> | ||
20 | |||
21 | #include "ecore_audio_private.h" | ||
22 | |||
23 | /* Ecore mainloop integration start */ | ||
24 | struct pa_io_event | ||
25 | { | ||
26 | pa_mainloop_api *mainloop; | ||
27 | Ecore_Fd_Handler *handler; | ||
28 | |||
29 | void *userdata; | ||
30 | |||
31 | pa_io_event_flags_t flags; | ||
32 | pa_io_event_cb_t callback; | ||
33 | pa_io_event_destroy_cb_t destroy_callback; | ||
34 | }; | ||
35 | |||
36 | static Ecore_Fd_Handler_Flags | ||
37 | map_flags_to_ecore(pa_io_event_flags_t flags) | ||
38 | { | ||
39 | return (Ecore_Fd_Handler_Flags)((flags & PA_IO_EVENT_INPUT ? ECORE_FD_READ : 0) | (flags & PA_IO_EVENT_OUTPUT ? ECORE_FD_WRITE : 0) | (flags & PA_IO_EVENT_ERROR ? ECORE_FD_ERROR : 0) | (flags & PA_IO_EVENT_HANGUP ? ECORE_FD_READ : 0)); | ||
40 | } | ||
41 | |||
42 | static Eina_Bool | ||
43 | _ecore_io_wrapper(void *data, Ecore_Fd_Handler *handler) | ||
44 | { | ||
45 | char buf[64]; | ||
46 | pa_io_event_flags_t flags = 0; | ||
47 | pa_io_event *event = (pa_io_event *)data; | ||
48 | |||
49 | if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) | ||
50 | { | ||
51 | flags |= PA_IO_EVENT_INPUT; | ||
52 | |||
53 | /* Check for HUP and report */ | ||
54 | if (recv(ecore_main_fd_handler_fd_get(handler), buf, 64, MSG_PEEK)) | ||
55 | { | ||
56 | if (errno == ESHUTDOWN || errno == ECONNRESET || errno == ECONNABORTED || errno == ENETRESET) | ||
57 | { | ||
58 | DBG("HUP condition detected"); | ||
59 | flags |= PA_IO_EVENT_HANGUP; | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | if (ecore_main_fd_handler_active_get(handler, ECORE_FD_WRITE)) | ||
65 | flags |= PA_IO_EVENT_OUTPUT; | ||
66 | if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) | ||
67 | flags |= PA_IO_EVENT_ERROR; | ||
68 | |||
69 | event->callback(event->mainloop, event, ecore_main_fd_handler_fd_get(handler), flags, event->userdata); | ||
70 | |||
71 | return ECORE_CALLBACK_RENEW; | ||
72 | } | ||
73 | |||
74 | static pa_io_event * | ||
75 | _ecore_pa_io_new(pa_mainloop_api *api, int fd, pa_io_event_flags_t flags, pa_io_event_cb_t cb, void *userdata) | ||
76 | { | ||
77 | pa_io_event *event; | ||
78 | |||
79 | event = calloc(1, sizeof(pa_io_event)); | ||
80 | event->mainloop = api; | ||
81 | event->userdata = userdata; | ||
82 | event->callback = cb; | ||
83 | event->flags = flags; | ||
84 | event->handler = ecore_main_fd_handler_add(fd, map_flags_to_ecore(flags), _ecore_io_wrapper, event, NULL, NULL); | ||
85 | |||
86 | return event; | ||
87 | } | ||
88 | |||
89 | static void | ||
90 | _ecore_pa_io_enable(pa_io_event *event, pa_io_event_flags_t flags) | ||
91 | { | ||
92 | event->flags = flags; | ||
93 | ecore_main_fd_handler_active_set(event->handler, map_flags_to_ecore(flags)); | ||
94 | } | ||
95 | |||
96 | static void | ||
97 | _ecore_pa_io_free(pa_io_event *event) | ||
98 | { | ||
99 | ecore_main_fd_handler_del(event->handler); | ||
100 | free(event); | ||
101 | } | ||
102 | |||
103 | static void | ||
104 | _ecore_pa_io_set_destroy(pa_io_event *event, pa_io_event_destroy_cb_t cb) | ||
105 | { | ||
106 | event->destroy_callback = cb; | ||
107 | } | ||
108 | |||
109 | /* Timed events */ | ||
110 | struct pa_time_event | ||
111 | { | ||
112 | pa_mainloop_api *mainloop; | ||
113 | Ecore_Timer *timer; | ||
114 | struct timeval tv; | ||
115 | |||
116 | void *userdata; | ||
117 | |||
118 | pa_time_event_cb_t callback; | ||
119 | pa_time_event_destroy_cb_t destroy_callback; | ||
120 | }; | ||
121 | |||
122 | Eina_Bool | ||
123 | _ecore_time_wrapper(void *data) | ||
124 | { | ||
125 | pa_time_event *event = (pa_time_event *)data; | ||
126 | |||
127 | event->callback(event->mainloop, event, &event->tv, event->userdata); | ||
128 | |||
129 | return ECORE_CALLBACK_CANCEL; | ||
130 | } | ||
131 | |||
132 | pa_time_event * | ||
133 | _ecore_pa_time_new(pa_mainloop_api *api, const struct timeval *tv, pa_time_event_cb_t cb, void *userdata) | ||
134 | { | ||
135 | pa_time_event *event; | ||
136 | struct timeval now; | ||
137 | double interval; | ||
138 | |||
139 | event = calloc(1, sizeof(pa_time_event)); | ||
140 | event->mainloop = api; | ||
141 | event->userdata = userdata; | ||
142 | event->callback = cb; | ||
143 | event->tv = *tv; | ||
144 | |||
145 | if (gettimeofday(&now, NULL) == -1) | ||
146 | { | ||
147 | ERR("Failed to get the current time!"); | ||
148 | return NULL; | ||
149 | } | ||
150 | |||
151 | interval = (tv->tv_sec - now.tv_sec) + (tv->tv_usec - now.tv_usec) / 1000; | ||
152 | event->timer = ecore_timer_add(interval, _ecore_time_wrapper, event); | ||
153 | |||
154 | return event; | ||
155 | } | ||
156 | |||
157 | void | ||
158 | _ecore_pa_time_restart(pa_time_event *event, const struct timeval *tv) | ||
159 | { | ||
160 | struct timeval now; | ||
161 | double interval; | ||
162 | |||
163 | /* If tv is NULL disable timer */ | ||
164 | if (!tv) | ||
165 | { | ||
166 | ecore_timer_del(event->timer); | ||
167 | event->timer = NULL; | ||
168 | return; | ||
169 | } | ||
170 | |||
171 | event->tv = *tv; | ||
172 | |||
173 | if (gettimeofday(&now, NULL) == -1) | ||
174 | { | ||
175 | ERR("Failed to get the current time!"); | ||
176 | return; | ||
177 | } | ||
178 | |||
179 | interval = (tv->tv_sec - now.tv_sec) + (tv->tv_usec - now.tv_usec) / 1000; | ||
180 | if (event->timer) | ||
181 | { | ||
182 | event->timer = ecore_timer_add(interval, _ecore_time_wrapper, event); | ||
183 | } | ||
184 | else | ||
185 | { | ||
186 | ecore_timer_interval_set(event->timer, interval); | ||
187 | ecore_timer_reset(event->timer); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | void | ||
192 | _ecore_pa_time_free(pa_time_event *event) | ||
193 | { | ||
194 | if (event->timer) | ||
195 | ecore_timer_del(event->timer); | ||
196 | |||
197 | event->timer = NULL; | ||
198 | |||
199 | free(event); | ||
200 | } | ||
201 | |||
202 | void | ||
203 | _ecore_pa_time_set_destroy(pa_time_event *event, pa_time_event_destroy_cb_t cb) | ||
204 | { | ||
205 | event->destroy_callback = cb; | ||
206 | } | ||
207 | |||
208 | /* Deferred events */ | ||
209 | struct pa_defer_event | ||
210 | { | ||
211 | pa_mainloop_api *mainloop; | ||
212 | Ecore_Idler *idler; | ||
213 | |||
214 | void *userdata; | ||
215 | |||
216 | pa_defer_event_cb_t callback; | ||
217 | pa_defer_event_destroy_cb_t destroy_callback; | ||
218 | }; | ||
219 | |||
220 | Eina_Bool | ||
221 | _ecore_defer_wrapper(void *data) | ||
222 | { | ||
223 | pa_defer_event *event = (pa_defer_event *)data; | ||
224 | |||
225 | event->idler = NULL; | ||
226 | event->callback(event->mainloop, event, event->userdata); | ||
227 | |||
228 | return ECORE_CALLBACK_CANCEL; | ||
229 | } | ||
230 | |||
231 | pa_defer_event * | ||
232 | _ecore_pa_defer_new(pa_mainloop_api *api, pa_defer_event_cb_t cb, void *userdata) | ||
233 | { | ||
234 | pa_defer_event *event; | ||
235 | |||
236 | event = calloc(1, sizeof(pa_defer_event)); | ||
237 | event->mainloop = api; | ||
238 | event->userdata = userdata; | ||
239 | event->callback = cb; | ||
240 | |||
241 | event->idler = ecore_idler_add(_ecore_defer_wrapper, event); | ||
242 | |||
243 | return event; | ||
244 | } | ||
245 | |||
246 | void | ||
247 | _ecore_pa_defer_enable(pa_defer_event *event, int b) | ||
248 | { | ||
249 | if (!b && event->idler) | ||
250 | { | ||
251 | ecore_idler_del(event->idler); | ||
252 | event->idler = NULL; | ||
253 | } | ||
254 | else if (b && !event->idler) | ||
255 | { | ||
256 | event->idler = ecore_idler_add(_ecore_defer_wrapper, event); | ||
257 | } | ||
258 | } | ||
259 | |||
260 | void | ||
261 | _ecore_pa_defer_free(pa_defer_event *event) | ||
262 | { | ||
263 | if (event->idler) | ||
264 | ecore_idler_del(event->idler); | ||
265 | |||
266 | event->idler = NULL; | ||
267 | |||
268 | free(event); | ||
269 | } | ||
270 | |||
271 | void | ||
272 | _ecore_pa_defer_set_destroy(pa_defer_event *event, pa_defer_event_destroy_cb_t cb) | ||
273 | { | ||
274 | event->destroy_callback = cb; | ||
275 | } | ||
276 | |||
277 | static void | ||
278 | _ecore_pa_quit(pa_mainloop_api *api EINA_UNUSED, int retval EINA_UNUSED) | ||
279 | { | ||
280 | /* FIXME: Need to clean up timers, etc.? */ | ||
281 | WRN("Not quitting mainloop, although PA requested it"); | ||
282 | } | ||
283 | |||
284 | /* Function table for PA mainloop integration */ | ||
285 | const pa_mainloop_api functable = { | ||
286 | .userdata = NULL, | ||
287 | |||
288 | .io_new = _ecore_pa_io_new, | ||
289 | .io_enable = _ecore_pa_io_enable, | ||
290 | .io_free = _ecore_pa_io_free, | ||
291 | .io_set_destroy = _ecore_pa_io_set_destroy, | ||
292 | |||
293 | .time_new = _ecore_pa_time_new, | ||
294 | .time_restart = _ecore_pa_time_restart, | ||
295 | .time_free = _ecore_pa_time_free, | ||
296 | .time_set_destroy = _ecore_pa_time_set_destroy, | ||
297 | |||
298 | .defer_new = _ecore_pa_defer_new, | ||
299 | .defer_enable = _ecore_pa_defer_enable, | ||
300 | .defer_free = _ecore_pa_defer_free, | ||
301 | .defer_set_destroy = _ecore_pa_defer_set_destroy, | ||
302 | |||
303 | .quit = _ecore_pa_quit, | ||
304 | }; | ||
305 | |||
306 | /* ***************************************************** | ||
307 | * Ecore mainloop integration end | ||
308 | */ | ||