]> code.delx.au - pulseaudio/blob - src/pulsecore/play-memchunk.c
make use of pa_thread_mq everywhere
[pulseaudio] / src / pulsecore / play-memchunk.c
1 /* $Id$ */
2
3 /***
4 This file is part of PulseAudio.
5
6 Copyright 2004-2006 Lennart Poettering
7
8 PulseAudio is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation; either version 2 of the License,
11 or (at your option) any later version.
12
13 PulseAudio is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with PulseAudio; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 USA.
22 ***/
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31
32 #include <pulse/xmalloc.h>
33
34 #include <pulsecore/sink-input.h>
35 #include <pulsecore/gccmacro.h>
36 #include <pulsecore/thread-mq.h>
37
38 #include "play-memchunk.h"
39
40 typedef struct memchunk_stream {
41 pa_msgobject parent;
42 pa_core *core;
43 pa_sink_input *sink_input;
44 pa_memchunk memchunk;
45 } memchunk_stream;
46
47 enum {
48 MEMCHUNK_STREAM_MESSAGE_UNLINK,
49 };
50
51 PA_DECLARE_CLASS(memchunk_stream);
52 #define MEMCHUNK_STREAM(o) (memchunk_stream_cast(o))
53 static PA_DEFINE_CHECK_TYPE(memchunk_stream, pa_msgobject);
54
55 static void memchunk_stream_unlink(memchunk_stream *u) {
56 pa_assert(u);
57
58 if (!u->sink_input)
59 return;
60
61 pa_sink_input_disconnect(u->sink_input);
62
63 pa_sink_input_unref(u->sink_input);
64 u->sink_input = NULL;
65
66 /* Make sure we don't decrease the ref count twice. */
67 memchunk_stream_unref(u);
68 }
69
70 static void memchunk_stream_free(pa_object *o) {
71 memchunk_stream *u = MEMCHUNK_STREAM(o);
72 pa_assert(u);
73
74 memchunk_stream_unlink(u);
75
76 if (u->memchunk.memblock)
77 pa_memblock_unref(u->memchunk.memblock);
78
79 pa_xfree(u);
80 }
81
82 static int memchunk_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
83 memchunk_stream *u = MEMCHUNK_STREAM(o);
84 memchunk_stream_assert_ref(u);
85
86 switch (code) {
87 case MEMCHUNK_STREAM_MESSAGE_UNLINK:
88 memchunk_stream_unlink(u);
89 break;
90 }
91
92 return 0;
93 }
94
95 static void sink_input_kill_cb(pa_sink_input *i) {
96 pa_sink_input_assert_ref(i);
97
98 memchunk_stream_unlink(MEMCHUNK_STREAM(i->userdata));
99 }
100
101 static int sink_input_peek_cb(pa_sink_input *i, pa_memchunk *chunk) {
102 memchunk_stream *u;
103
104 pa_assert(i);
105 pa_assert(chunk);
106 u = MEMCHUNK_STREAM(i->userdata);
107 memchunk_stream_assert_ref(u);
108
109 if (!u->memchunk.memblock)
110 return -1;
111
112 if (u->memchunk.length <= 0) {
113 pa_memblock_unref(u->memchunk.memblock);
114 u->memchunk.memblock = NULL;
115 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), MEMCHUNK_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL);
116 return -1;
117 }
118
119 pa_assert(u->memchunk.memblock);
120 *chunk = u->memchunk;
121 pa_memblock_ref(chunk->memblock);
122
123 return 0;
124 }
125
126 static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
127 memchunk_stream *u;
128
129 pa_assert(i);
130 pa_assert(length > 0);
131 u = MEMCHUNK_STREAM(i->userdata);
132 memchunk_stream_assert_ref(u);
133
134 if (length < u->memchunk.length) {
135 u->memchunk.length -= length;
136 u->memchunk.index += length;
137 } else
138 u->memchunk.length = 0;
139 }
140
141 int pa_play_memchunk(
142 pa_sink *sink,
143 const char *name,
144 const pa_sample_spec *ss,
145 const pa_channel_map *map,
146 const pa_memchunk *chunk,
147 pa_cvolume *volume) {
148
149 memchunk_stream *u = NULL;
150 pa_sink_input_new_data data;
151
152 pa_assert(sink);
153 pa_assert(ss);
154 pa_assert(chunk);
155
156 if (volume && pa_cvolume_is_muted(volume))
157 return 0;
158
159 u = pa_msgobject_new(memchunk_stream);
160 u->parent.parent.free = memchunk_stream_free;
161 u->parent.process_msg = memchunk_stream_process_msg;
162 u->core = sink->core;
163 u->sink_input = NULL;
164 u->memchunk = *chunk;
165 pa_memblock_ref(u->memchunk.memblock);
166
167 pa_sink_input_new_data_init(&data);
168 data.sink = sink;
169 data.driver = __FILE__;
170 data.name = name;
171 pa_sink_input_new_data_set_sample_spec(&data, ss);
172 pa_sink_input_new_data_set_channel_map(&data, map);
173 pa_sink_input_new_data_set_volume(&data, volume);
174
175 if (!(u->sink_input = pa_sink_input_new(sink->core, &data, 0)))
176 goto fail;
177
178 u->sink_input->peek = sink_input_peek_cb;
179 u->sink_input->drop = sink_input_drop_cb;
180 u->sink_input->kill = sink_input_kill_cb;
181 u->sink_input->userdata = u;
182
183 pa_sink_input_put(u->sink_input);
184
185 /* The reference to u is dangling here, because we want to keep
186 * this stream around until it is fully played. */
187
188 return 0;
189
190 fail:
191 if (u)
192 memchunk_stream_unref(u);
193
194 return -1;
195 }
196