make SwfdecSandbox a relay
[swfdec.git] / swfdec / swfdec_load_sound.c
blob9b46be11eb8ef04a6504cd8d807f047f070c77d7
1 /* Swfdec
2 * Copyright (C) 2003, 2008 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include "swfdec_load_sound.h"
25 #include "swfdec_access.h"
26 #include "swfdec_as_strings.h"
27 #include "swfdec_audio_decoder.h"
28 #include "swfdec_audio_internal.h"
29 #include "swfdec_audio_load.h"
30 #include "swfdec_bits.h"
31 #include "swfdec_buffer.h"
32 #include "swfdec_debug.h"
33 #include "swfdec_loader_internal.h"
34 #include "swfdec_player_internal.h"
35 #include "swfdec_sandbox.h"
36 #include "swfdec_sound_provider.h"
37 #include "swfdec_stream_target.h"
39 /*** SWFDEC_SOUND_PROVIDER ***/
41 static void
42 swfdec_load_sound_sound_provider_start (SwfdecSoundProvider *provider,
43 SwfdecActor *actor, gsize samples_offset, guint loops)
45 SwfdecLoadSound *sound = SWFDEC_LOAD_SOUND (provider);
47 if (sound->audio) {
48 swfdec_audio_remove (sound->audio);
49 g_object_unref (sound->audio);
51 if (samples_offset > 0 || loops > 1) {
52 SWFDEC_FIXME ("implement starting at offset %"G_GSIZE_FORMAT" with %u loops",
53 samples_offset, loops);
55 sound->audio = swfdec_audio_load_new (SWFDEC_PLAYER (swfdec_gc_object_get_context (actor)), sound);
56 swfdec_audio_set_matrix (sound->audio, &sound->sound_matrix);
59 static void
60 swfdec_load_sound_sound_provider_stop (SwfdecSoundProvider *provider, SwfdecActor *actor)
62 SwfdecLoadSound *sound = SWFDEC_LOAD_SOUND (provider);
64 if (sound->audio == NULL)
65 return;
67 swfdec_audio_set_matrix (sound->audio, NULL);
68 swfdec_audio_remove (sound->audio);
69 g_object_unref (sound->audio);
70 sound->audio = NULL;
73 static SwfdecSoundMatrix *
74 swfdec_load_sound_sound_provider_get_matrix (SwfdecSoundProvider *provider)
76 SwfdecLoadSound *sound = SWFDEC_LOAD_SOUND (provider);
78 return &sound->sound_matrix;
81 static void
82 swfdec_load_sound_sound_provider_init (SwfdecSoundProviderInterface *iface)
84 iface->start = swfdec_load_sound_sound_provider_start;
85 iface->stop = swfdec_load_sound_sound_provider_stop;
86 iface->get_matrix = swfdec_load_sound_sound_provider_get_matrix;
89 /*** SWFDEC_STREAM_TARGET ***/
91 static SwfdecPlayer *
92 swfdec_load_sound_stream_target_get_player (SwfdecStreamTarget *target)
94 return SWFDEC_PLAYER (swfdec_gc_object_get_context (SWFDEC_LOAD_SOUND (target)->target));
97 static gboolean
98 swfdec_load_sound_mp3_parse_id3v2 (SwfdecLoadSound *sound, SwfdecBufferQueue *queue)
100 SwfdecBuffer *buffer;
101 SwfdecBits bits;
102 guint size;
103 gboolean footer;
105 buffer = swfdec_buffer_queue_peek (queue, 10);
106 if (buffer == NULL)
107 return FALSE;
108 swfdec_bits_init (&bits, buffer);
109 if (swfdec_bits_get_u8 (&bits) != 'I' ||
110 swfdec_bits_get_u8 (&bits) != 'D' ||
111 swfdec_bits_get_u8 (&bits) != '3')
112 goto error;
113 /* version = */ swfdec_bits_get_u16 (&bits);
114 /* flags = */ swfdec_bits_getbits (&bits, 3);
115 footer = swfdec_bits_getbit (&bits);
116 /* reserved = */ swfdec_bits_getbits (&bits, 4);
117 size = swfdec_bits_get_bu32 (&bits);
118 if (size & 0x80808080)
119 goto error;
120 size = ((size & 0xFF000000) >> 3) |
121 ((size & 0xFF0000) >> 2) |
122 ((size & 0xFF00) >> 1) | (size & 0xFF);
123 swfdec_buffer_unref (buffer);
125 buffer = swfdec_buffer_queue_pull (queue, 10 + size + (footer ? 10 : 0));
126 if (buffer == NULL)
127 return FALSE;
128 SWFDEC_FIXME ("implement ID3v2 parsing");
129 SWFDEC_LOG ("%"G_GSIZE_FORMAT" bytes ID3v2", buffer->length);
130 swfdec_buffer_unref (buffer);
131 return TRUE;
133 error:
134 swfdec_buffer_unref (buffer);
135 swfdec_buffer_queue_flush (queue, 1);
136 return TRUE;
139 static gboolean
140 swfdec_load_sound_mp3_parse_id3v1 (SwfdecLoadSound *sound, SwfdecBufferQueue *queue)
142 SwfdecBuffer *buffer;
144 buffer = swfdec_buffer_queue_pull (queue, 128);
145 if (buffer == NULL)
146 return FALSE;
148 if (buffer->data[0] != 'T' ||
149 buffer->data[1] != 'A' ||
150 buffer->data[2] != 'G') {
151 swfdec_buffer_unref (buffer);
152 swfdec_buffer_queue_flush (queue, 1);
153 return TRUE;
155 SWFDEC_FIXME ("implement ID3v1 parsing");
156 swfdec_buffer_unref (buffer);
157 return TRUE;
160 static gboolean
161 swfdec_load_sound_mp3_parse_frame (SwfdecLoadSound *sound, SwfdecBufferQueue *queue)
163 static const guint mp3types_bitrates[2][3][16] = {
164 { {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, },
165 {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, },
166 {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, }},
167 { {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, },
168 {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, },
169 {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, }}
171 static const guint mp3types_freqs[3][3] = {
172 { 11025, 12000, 8000 },
173 { 22050, 24000, 16000 },
174 { 44100, 48000, 32000 }
177 SwfdecBuffer *buffer;
178 SwfdecBits bits;
179 guint version, layer, bitrate, samplerate, length, channels;
181 buffer = swfdec_buffer_queue_peek (queue, 4);
182 if (buffer == NULL)
183 return FALSE;
185 swfdec_bits_init (&bits, buffer);
186 if (swfdec_bits_getbits (&bits, 11) != 0x7FF)
187 goto error;
189 version = swfdec_bits_getbits (&bits, 2);
190 if (version == 1)
191 goto error;
192 layer = 4 - swfdec_bits_getbits (&bits, 2);
193 if (layer == 4)
194 goto error;
195 /* has_crc = */ swfdec_bits_getbit (&bits);
196 bitrate = swfdec_bits_getbits (&bits, 4);
197 if (bitrate == 0 || bitrate == 15) {
198 if (bitrate == 0) {
199 SWFDEC_FIXME ("need to support free frame length?");
201 goto error;
203 samplerate = swfdec_bits_getbits (&bits, 2);
204 if (samplerate == 3)
205 goto error;
206 length = swfdec_bits_getbits (&bits, 1);
207 /* unused = */ swfdec_bits_getbits (&bits, 1);
208 channels = swfdec_bits_getbits (&bits, 2) == 3 ? 1 : 2;
210 samplerate = mp3types_freqs[version > 0 ? version - 1 : 0][samplerate];
211 bitrate = mp3types_bitrates[version == 3 ? 0 : 1][layer - 1][bitrate];
212 if (layer == 1) {
213 length = ((12000 * bitrate / samplerate) + length) * 4;
214 } else {
215 length += ((layer == 3 && version != 3) ? 72000 : 144000)
216 * bitrate / samplerate;
218 swfdec_buffer_unref (buffer);
220 SWFDEC_LOG ("adding %u bytes mp3 frame", length);
221 buffer = swfdec_buffer_queue_pull (queue, length);
222 if (buffer == NULL)
223 return FALSE;
225 g_ptr_array_add (sound->frames, buffer);
226 return TRUE;
228 error:
229 swfdec_buffer_unref (buffer);
230 swfdec_buffer_queue_flush (queue, 1);
231 return TRUE;
234 static gboolean
235 swfdec_load_sound_stream_target_parse (SwfdecStreamTarget *target,
236 SwfdecStream *stream)
238 SwfdecLoadSound *sound = SWFDEC_LOAD_SOUND (target);
239 SwfdecBufferQueue *queue;
240 SwfdecBuffer *buffer;
241 guint i;
242 gboolean go_on = TRUE;
244 /* decode MP3 into frames, ID3 tags and crap */
245 queue = swfdec_stream_get_queue (stream);
246 do {
247 /* sync */
248 buffer = swfdec_buffer_queue_peek_buffer (queue);
249 if (buffer == NULL)
250 break;
251 for (i = 0; i < buffer->length; i++) {
252 if (buffer->data[i] == 'I' || buffer->data[i] == 'T' || buffer->data[i] == 0xFF)
253 break;
255 if (i) {
256 SWFDEC_LOG ("sync: flushing %u bytes", i);
258 swfdec_buffer_queue_flush (queue, i);
259 if (i == buffer->length) {
260 swfdec_buffer_unref (buffer);
261 continue;
263 /* parse data */
264 switch (buffer->data[i]) {
265 case 'I':
266 /* ID3v2 */
267 go_on = swfdec_load_sound_mp3_parse_id3v2 (sound, queue);
268 break;
269 case 'T':
270 /* ID3v1 */
271 go_on = swfdec_load_sound_mp3_parse_id3v1 (sound, queue);
272 break;
273 case 0xFF:
274 /* MP3 frame */
275 go_on = swfdec_load_sound_mp3_parse_frame (sound, queue);
276 break;
277 default:
278 /* skip - and yes, the continue refers to the for loop */
279 continue;
281 swfdec_buffer_unref (buffer);
282 } while (go_on);
283 return FALSE;
286 static void
287 swfdec_load_sound_stream_target_error (SwfdecStreamTarget *target,
288 SwfdecStream *stream)
290 SwfdecLoadSound *sound = SWFDEC_LOAD_SOUND (target);
291 SwfdecAsValue val;
293 SWFDEC_AS_VALUE_SET_BOOLEAN (&val, FALSE);
294 swfdec_sandbox_use (sound->sandbox);
295 swfdec_as_object_call (sound->target, SWFDEC_AS_STR_onLoad, 1, &val, NULL);
296 swfdec_sandbox_unuse (sound->sandbox);
298 swfdec_stream_set_target (stream, NULL);
299 g_object_unref (stream);
300 sound->stream = NULL;
303 static void
304 swfdec_load_sound_stream_target_close (SwfdecStreamTarget *target,
305 SwfdecStream *stream)
307 SwfdecLoadSound *sound = SWFDEC_LOAD_SOUND (target);
308 SwfdecAsValue val;
310 swfdec_stream_set_target (stream, NULL);
311 g_object_unref (stream);
312 sound->stream = NULL;
314 SWFDEC_AS_VALUE_SET_BOOLEAN (&val, TRUE);
315 swfdec_sandbox_use (sound->sandbox);
316 swfdec_as_object_call (sound->target, SWFDEC_AS_STR_onLoad, 1, &val, NULL);
317 swfdec_sandbox_unuse (sound->sandbox);
320 static void
321 swfdec_load_sound_stream_target_init (SwfdecStreamTargetInterface *iface)
323 iface->get_player = swfdec_load_sound_stream_target_get_player;
324 iface->parse = swfdec_load_sound_stream_target_parse;
325 iface->close = swfdec_load_sound_stream_target_close;
326 iface->error = swfdec_load_sound_stream_target_error;
329 /*** SWFDEC_LOAD_SOUND ***/
331 G_DEFINE_TYPE_WITH_CODE (SwfdecLoadSound, swfdec_load_sound, G_TYPE_OBJECT,
332 G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_STREAM_TARGET, swfdec_load_sound_stream_target_init);
333 G_IMPLEMENT_INTERFACE (SWFDEC_TYPE_SOUND_PROVIDER, swfdec_load_sound_sound_provider_init))
335 static void
336 swfdec_load_sound_dispose (GObject *object)
338 SwfdecLoadSound *sound = SWFDEC_LOAD_SOUND (object);
340 g_ptr_array_foreach (sound->frames, (GFunc) swfdec_buffer_unref, NULL);
341 g_ptr_array_free (sound->frames, TRUE);
342 if (sound->stream) {
343 swfdec_stream_set_target (sound->stream, NULL);
344 g_object_unref (sound->stream);
345 sound->stream = NULL;
347 g_free (sound->url);
348 if (sound->audio) {
349 swfdec_audio_set_matrix (sound->audio, NULL);
350 swfdec_audio_remove (sound->audio);
351 g_object_unref (sound->audio);
352 sound->audio = NULL;
355 G_OBJECT_CLASS (swfdec_load_sound_parent_class)->dispose (object);
358 static void
359 swfdec_load_sound_class_init (SwfdecLoadSoundClass *klass)
361 GObjectClass *object_class = G_OBJECT_CLASS (klass);
363 object_class->dispose = swfdec_load_sound_dispose;
366 static void
367 swfdec_load_sound_init (SwfdecLoadSound *sound)
369 sound->frames = g_ptr_array_new ();
371 swfdec_sound_matrix_init_identity (&sound->sound_matrix);
374 static void
375 swfdec_load_sound_load (SwfdecPlayer *player, gboolean allow, gpointer data)
377 SwfdecLoadSound *sound = data;
379 if (!allow) {
380 SwfdecAsValue val;
382 SWFDEC_WARNING ("SECURITY: no access to %s from Sound.loadSound",
383 sound->url);
384 SWFDEC_AS_VALUE_SET_BOOLEAN (&val, FALSE);
385 return;
388 sound->stream = SWFDEC_STREAM (swfdec_player_load (player, sound->url, NULL));
389 swfdec_stream_set_target (sound->stream, SWFDEC_STREAM_TARGET (sound));
392 static const SwfdecAccessMatrix swfdec_load_sound_matrix = {
393 { SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO },
394 { SWFDEC_ACCESS_NO, SWFDEC_ACCESS_YES, SWFDEC_ACCESS_YES },
395 { SWFDEC_ACCESS_YES, SWFDEC_ACCESS_NO, SWFDEC_ACCESS_NO },
396 { SWFDEC_ACCESS_YES, SWFDEC_ACCESS_YES, SWFDEC_ACCESS_YES },
397 { SWFDEC_ACCESS_YES, SWFDEC_ACCESS_YES, SWFDEC_ACCESS_YES }
400 SwfdecLoadSound *
401 swfdec_load_sound_new (SwfdecAsObject *target, const char *url)
403 SwfdecLoadSound *sound;
404 SwfdecAsContext *context;
405 char *missing;
407 g_return_val_if_fail (SWFDEC_IS_AS_OBJECT (target), NULL);
408 g_return_val_if_fail (url != NULL, NULL);
410 context = swfdec_gc_object_get_context (target);
411 sound = g_object_new (SWFDEC_TYPE_LOAD_SOUND, NULL);
412 sound->target = target;
413 sound->sandbox = swfdec_sandbox_get (SWFDEC_PLAYER (context));
414 sound->url = g_strdup (url);
415 g_assert (sound->sandbox);
416 swfdec_player_allow_by_matrix (SWFDEC_PLAYER (context), sound->sandbox,
417 url, swfdec_load_sound_matrix, swfdec_load_sound_load, sound);
418 /* tell missing plugins stuff we want MP3 */
419 missing = NULL;
420 swfdec_audio_decoder_prepare (SWFDEC_AUDIO_CODEC_MP3,
421 swfdec_audio_format_new (44100, 2, TRUE), &missing);
422 if (missing) {
423 swfdec_player_add_missing_plugin (SWFDEC_PLAYER (context),
424 missing);
425 g_free (missing);
428 return sound;