2 * Copyright (C) 2003-2006 David Schleef <ds@schleef.org>
3 * 2005-2006 Eric Anholt <eric@anholt.net>
4 * 2006 Benjamin Otte <otte@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
27 #include "swfdec_audio_stream.h"
28 #include "swfdec_debug.h"
29 #include "swfdec_sound.h"
30 #include "swfdec_sprite.h"
33 G_DEFINE_TYPE (SwfdecAudioStream
, swfdec_audio_stream
, SWFDEC_TYPE_AUDIO
)
36 swfdec_audio_stream_dispose (GObject
*object
)
38 SwfdecAudioStream
*stream
= SWFDEC_AUDIO_STREAM (object
);
40 if (stream
->decoder
!= NULL
) {
41 g_object_unref (stream
->decoder
);
42 stream
->decoder
= NULL
;
44 g_queue_foreach (stream
->queue
, (GFunc
) swfdec_buffer_unref
, NULL
);
45 g_queue_free (stream
->queue
);
47 G_OBJECT_CLASS (swfdec_audio_stream_parent_class
)->dispose (object
);
50 /* returns: number of samples available */
52 swfdec_audio_stream_require (SwfdecAudioStream
*stream
, guint n_samples
)
54 SwfdecAudioStreamClass
*klass
= SWFDEC_AUDIO_STREAM_GET_CLASS (stream
);
57 /* subclasses are responsible for having set a proper decoder */
58 g_assert (SWFDEC_IS_AUDIO_DECODER (stream
->decoder
));
60 while (stream
->queue_size
< n_samples
&& !stream
->done
) {
61 /* if the decoder still has data */
62 buffer
= swfdec_audio_decoder_pull (stream
->decoder
);
64 g_queue_push_tail (stream
->queue
, buffer
);
65 stream
->queue_size
+= buffer
->length
/ 4;
68 /* otherwise get a new buffer from the decoder */
69 buffer
= klass
->pull (stream
);
71 stream
->buffering
= TRUE
;
74 swfdec_audio_decoder_push (stream
->decoder
, buffer
);
75 swfdec_buffer_unref (buffer
);
80 swfdec_audio_stream_render (SwfdecAudio
*audio
, gint16
* dest
,
81 gsize start
, gsize n_samples
)
83 SwfdecAudioStream
*stream
= SWFDEC_AUDIO_STREAM (audio
);
85 gsize samples
, rendered
, skip
;
88 g_assert (start
< G_MAXINT
);
89 SWFDEC_LOG ("stream %p rendering offset %"G_GSIZE_FORMAT
", samples %"G_GSIZE_FORMAT
,
90 stream
, start
, n_samples
);
91 swfdec_audio_stream_require (stream
, start
+ n_samples
);
92 if (stream
->queue_size
<= start
)
94 n_samples
= MIN (stream
->queue_size
, n_samples
+ start
);
97 for (walk
= g_queue_peek_head_link (stream
->queue
);
98 rendered
< n_samples
; walk
= walk
->next
) {
99 /* must hold, we check above that enough data is available */
102 samples
= buffer
->length
/ 4;
103 if (rendered
< start
) {
104 skip
= MIN (samples
, start
- rendered
);
106 samples
= MIN (n_samples
- start
, samples
);
109 samples
= MIN (n_samples
- rendered
, samples
);
111 samples
= MIN (n_samples
- MAX (start
, rendered
), samples
);
113 swfdec_sound_buffer_render (dest
, buffer
, skip
, samples
);
115 rendered
+= skip
+ samples
;
119 return rendered
- start
;
123 swfdec_audio_stream_check_buffering (SwfdecAudioStream
*stream
)
125 SwfdecAudioStreamClass
*klass
;
126 SwfdecBuffer
*buffer
;
128 if (!stream
->buffering
|| stream
->done
)
131 klass
= SWFDEC_AUDIO_STREAM_GET_CLASS (stream
);
132 buffer
= klass
->pull (stream
);
136 swfdec_audio_decoder_push (stream
->decoder
, buffer
);
137 swfdec_buffer_unref (buffer
);
138 stream
->buffering
= FALSE
;
139 g_signal_emit_by_name (stream
, "new-data");
140 return stream
->queue_size
== 0;
144 swfdec_audio_stream_iterate (SwfdecAudio
*audio
, gsize remove
)
146 SwfdecAudioStream
*stream
= SWFDEC_AUDIO_STREAM (audio
);
147 SwfdecBuffer
*buffer
;
148 gsize samples
, cur_samples
;
150 if (swfdec_audio_stream_check_buffering (stream
))
152 swfdec_audio_stream_require (stream
, remove
);
153 samples
= MIN (remove
, stream
->queue_size
);
155 while (samples
> 0) {
156 buffer
= g_queue_pop_head (stream
->queue
);
157 cur_samples
= buffer
->length
/ 4;
158 if (samples
< cur_samples
) {
159 SwfdecBuffer
*sub
= swfdec_buffer_new_subbuffer (buffer
,
160 samples
* 4, buffer
->length
- samples
* 4);
161 g_queue_push_head (stream
->queue
, sub
);
162 cur_samples
= samples
;
164 stream
->queue_size
-= cur_samples
;
165 samples
-= cur_samples
;
171 return stream
->queue_size
;
176 swfdec_audio_stream_class_init (SwfdecAudioStreamClass
*klass
)
178 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
179 SwfdecAudioClass
*audio_class
= SWFDEC_AUDIO_CLASS (klass
);
181 object_class
->dispose
= swfdec_audio_stream_dispose
;
183 audio_class
->iterate
= swfdec_audio_stream_iterate
;
184 audio_class
->render
= swfdec_audio_stream_render
;
188 swfdec_audio_stream_init (SwfdecAudioStream
*stream
)
190 stream
->queue
= g_queue_new ();
194 swfdec_audio_stream_use_decoder (SwfdecAudioStream
*stream
,
195 guint codec
, SwfdecAudioFormat format
)
197 g_return_if_fail (SWFDEC_IS_AUDIO_STREAM (stream
));
198 g_return_if_fail (SWFDEC_IS_AUDIO_FORMAT (format
));
200 if (stream
->decoder
) {
201 if (swfdec_audio_decoder_uses_format (stream
->decoder
, codec
, format
))
203 /* FIXME: send NULL buffer */
204 g_object_unref (stream
->decoder
);
206 stream
->decoder
= swfdec_audio_decoder_new (codec
, format
);
210 swfdec_audio_stream_done (SwfdecAudioStream
*stream
)
212 g_return_if_fail (SWFDEC_IS_AUDIO_STREAM (stream
));
213 g_return_if_fail (!stream
->done
);