4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
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.
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.
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
32 #include <pulse/xmalloc.h>
34 #include <pulsecore/sink-input.h>
35 #include <pulsecore/gccmacro.h>
36 #include <pulsecore/thread-mq.h>
38 #include "play-memchunk.h"
40 typedef struct memchunk_stream
{
43 pa_sink_input
*sink_input
;
48 MEMCHUNK_STREAM_MESSAGE_UNLINK
,
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
);
55 static void memchunk_stream_unlink(memchunk_stream
*u
) {
61 pa_sink_input_disconnect(u
->sink_input
);
63 pa_sink_input_unref(u
->sink_input
);
66 /* Make sure we don't decrease the ref count twice. */
67 memchunk_stream_unref(u
);
70 static void memchunk_stream_free(pa_object
*o
) {
71 memchunk_stream
*u
= MEMCHUNK_STREAM(o
);
74 memchunk_stream_unlink(u
);
76 if (u
->memchunk
.memblock
)
77 pa_memblock_unref(u
->memchunk
.memblock
);
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
);
87 case MEMCHUNK_STREAM_MESSAGE_UNLINK
:
88 memchunk_stream_unlink(u
);
95 static void sink_input_kill_cb(pa_sink_input
*i
) {
96 pa_sink_input_assert_ref(i
);
98 memchunk_stream_unlink(MEMCHUNK_STREAM(i
->userdata
));
101 static int sink_input_peek_cb(pa_sink_input
*i
, pa_memchunk
*chunk
) {
106 u
= MEMCHUNK_STREAM(i
->userdata
);
107 memchunk_stream_assert_ref(u
);
109 if (!u
->memchunk
.memblock
)
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
);
119 pa_assert(u
->memchunk
.memblock
);
120 *chunk
= u
->memchunk
;
121 pa_memblock_ref(chunk
->memblock
);
126 static void sink_input_drop_cb(pa_sink_input
*i
, size_t length
) {
130 pa_assert(length
> 0);
131 u
= MEMCHUNK_STREAM(i
->userdata
);
132 memchunk_stream_assert_ref(u
);
134 if (length
< u
->memchunk
.length
) {
135 u
->memchunk
.length
-= length
;
136 u
->memchunk
.index
+= length
;
138 u
->memchunk
.length
= 0;
141 int pa_play_memchunk(
144 const pa_sample_spec
*ss
,
145 const pa_channel_map
*map
,
146 const pa_memchunk
*chunk
,
147 pa_cvolume
*volume
) {
149 memchunk_stream
*u
= NULL
;
150 pa_sink_input_new_data data
;
156 if (volume
&& pa_cvolume_is_muted(volume
))
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
);
167 pa_sink_input_new_data_init(&data
);
169 data
.driver
= __FILE__
;
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
);
175 if (!(u
->sink_input
= pa_sink_input_new(sink
->core
, &data
, 0)))
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
;
183 pa_sink_input_put(u
->sink_input
);
185 /* The reference to u is dangling here, because we want to keep
186 * this stream around until it is fully played. */
192 memchunk_stream_unref(u
);