]> code.delx.au - pulseaudio/blob - src/pulsecore/play-memchunk.c
merge 'lennart' branch back into trunk.
[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_unlink(u->sink_input);
62
63 pa_sink_input_unref(u->sink_input);
64 u->sink_input = NULL;
65
66 memchunk_stream_unref(u);
67 }
68
69 static void memchunk_stream_free(pa_object *o) {
70 memchunk_stream *u = MEMCHUNK_STREAM(o);
71 pa_assert(u);
72
73 memchunk_stream_unlink(u);
74
75 if (u->memchunk.memblock)
76 pa_memblock_unref(u->memchunk.memblock);
77
78 pa_xfree(u);
79 }
80
81 static int memchunk_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) {
82 memchunk_stream *u = MEMCHUNK_STREAM(o);
83 memchunk_stream_assert_ref(u);
84
85 switch (code) {
86 case MEMCHUNK_STREAM_MESSAGE_UNLINK:
87 memchunk_stream_unlink(u);
88 break;
89 }
90
91 return 0;
92 }
93
94 static void sink_input_kill_cb(pa_sink_input *i) {
95 pa_sink_input_assert_ref(i);
96
97 memchunk_stream_unlink(MEMCHUNK_STREAM(i->userdata));
98 }
99
100 static int sink_input_peek_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
101 memchunk_stream *u;
102
103 pa_assert(i);
104 pa_assert(chunk);
105 u = MEMCHUNK_STREAM(i->userdata);
106 memchunk_stream_assert_ref(u);
107
108 if (!u->memchunk.memblock)
109 return -1;
110
111 if (u->memchunk.length <= 0) {
112 pa_memblock_unref(u->memchunk.memblock);
113 u->memchunk.memblock = NULL;
114 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(u), MEMCHUNK_STREAM_MESSAGE_UNLINK, NULL, 0, NULL, NULL);
115 return -1;
116 }
117
118 pa_assert(u->memchunk.memblock);
119 *chunk = u->memchunk;
120 pa_memblock_ref(chunk->memblock);
121
122 return 0;
123 }
124
125 static void sink_input_drop_cb(pa_sink_input *i, size_t length) {
126 memchunk_stream *u;
127
128 pa_assert(i);
129 pa_assert(length > 0);
130 u = MEMCHUNK_STREAM(i->userdata);
131 memchunk_stream_assert_ref(u);
132
133 if (length < u->memchunk.length) {
134 u->memchunk.length -= length;
135 u->memchunk.index += length;
136 } else
137 u->memchunk.length = 0;
138 }
139
140 int pa_play_memchunk(
141 pa_sink *sink,
142 const char *name,
143 const pa_sample_spec *ss,
144 const pa_channel_map *map,
145 const pa_memchunk *chunk,
146 pa_cvolume *volume) {
147
148 memchunk_stream *u = NULL;
149 pa_sink_input_new_data data;
150
151 pa_assert(sink);
152 pa_assert(ss);
153 pa_assert(chunk);
154
155 if (volume && pa_cvolume_is_muted(volume))
156 return 0;
157
158 pa_memchunk_will_need(chunk);
159
160 u = pa_msgobject_new(memchunk_stream);
161 u->parent.parent.free = memchunk_stream_free;
162 u->parent.process_msg = memchunk_stream_process_msg;
163 u->core = sink->core;
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