add a test for just-fixed crasher
[swfdec.git] / swfdec / swfdec_audio.c
blob260eb4244fcf971d0aea2a33f3713fe1b417c637
1 /* Swfdec
2 * Copyright (C) 2003-2006 David Schleef <ds@schleef.org>
3 * 2005-2006 Eric Anholt <eric@anholt.net>
4 * 2006-2008 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
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #include <string.h>
27 #include "swfdec_audio_internal.h"
28 #include "swfdec_actor.h"
29 #include "swfdec_debug.h"
30 #include "swfdec_player_internal.h"
32 /**
33 * SECTION:SwfdecAudio
34 * @title: SwfdecAudio
35 * @see_also: SwfdecPlayer
36 * @short_description: object used for audio output
38 * SwfdecAudio is the way audio output is provided by a #SwfdecPlayer. See
39 * its documentation on how to access #SwfdecAudio objects.
41 * An audio object gives access to one audio stream played inside a player.
42 * You are responsible for outputting this data, swfdec does not try to do this
43 * for you.
45 * Audio data is always provided in 16bit host-endian stereo. If the data was
46 * encoded into a different format originally, Swfdec will already have decoded
47 * it. The data is always referenced relative to the player. Sample 0
48 * references the first sample to be played at the current position. If the
49 * player gets iterated, sample 0 changes. There is no way to access samples
50 * belonging to a previous state.
53 /**
54 * SwfdecAudio
56 * This object is used for audio output. It is an abstract class.
59 G_DEFINE_ABSTRACT_TYPE (SwfdecAudio, swfdec_audio, G_TYPE_OBJECT)
61 enum {
62 CHANGED,
63 NEW_DATA,
64 LAST_SIGNAL
67 static guint signals[LAST_SIGNAL] = { 0, };
69 static void
70 swfdec_audio_dispose (GObject *object)
72 SwfdecAudio *audio = SWFDEC_AUDIO (object);
74 g_assert (audio->actor == NULL);
75 g_assert (audio->player == NULL);
77 G_OBJECT_CLASS (swfdec_audio_parent_class)->dispose (object);
80 static void
81 swfdec_audio_class_init (SwfdecAudioClass *klass)
83 GObjectClass *object_class = G_OBJECT_CLASS (klass);
85 /**
86 * SwfdecAudio::changed:
87 * @audio: the #SwfdecAudio affected
89 * This signal is emitted whenever the data of the @audio changed and cached
90 * data should be rerendered. This happens for example when the volume of the
91 * audio is changed by the Flash file.
93 signals[CHANGED] = g_signal_new ("changed", G_TYPE_FROM_CLASS (klass),
94 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
95 G_TYPE_NONE, 0);
96 /**
97 * SwfdecAudio::new-data:
98 * @audio: the #SwfdecAudio affected
100 * This signal is emitted whenever new data was loaded into @audio. You want
101 * to listen to this signal when swfdec_audio_render() previously returned
102 * less samples than you wanted to render.
104 signals[NEW_DATA] = g_signal_new ("new-data", G_TYPE_FROM_CLASS (klass),
105 G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
106 G_TYPE_NONE, 0);
108 object_class->dispose = swfdec_audio_dispose;
111 static void
112 swfdec_audio_init (SwfdecAudio *audio)
117 * swfdec_audio_add:
118 * @audio: audio to add
119 * @player: a #SwfdecPlayer to attach to or NULL
121 * Registers a new audio object for playback in @player. If player is %NULL,
122 * this function does nothing.
123 * The starting point of the audio stream will be equivalent the player's time.
125 void
126 swfdec_audio_add (SwfdecAudio *audio, SwfdecPlayer *player)
128 SwfdecPlayerPrivate *priv;
130 g_return_if_fail (SWFDEC_IS_AUDIO (audio));
131 g_return_if_fail (audio->player == NULL);
132 if (player == NULL)
133 return;
134 g_return_if_fail (SWFDEC_IS_PLAYER (player));
136 g_object_ref (audio);
137 audio->player = player;
138 priv = player->priv;
139 priv->audio = g_list_append (priv->audio, audio);
140 SWFDEC_INFO ("adding %s %p", G_OBJECT_TYPE_NAME (audio), audio);
143 void
144 swfdec_audio_remove (SwfdecAudio *audio)
146 g_return_if_fail (SWFDEC_IS_AUDIO (audio));
148 if (audio->player != NULL) {
149 SwfdecPlayerPrivate *priv = audio->player->priv;
150 SWFDEC_INFO ("removing %s %p", G_OBJECT_TYPE_NAME (audio), audio);
151 swfdec_audio_set_actor (audio, NULL);
152 priv->audio = g_list_remove (priv->audio, audio);
153 if (audio->added) {
154 g_signal_emit_by_name (audio->player, "audio-removed", audio);
155 audio->added = FALSE;
157 audio->player = NULL;
158 g_object_unref (audio);
163 * swfdec_audio_iterate:
164 * @audio: the #SwfdecAudio to iterate
165 * @n_samples: number of samples to remove
167 * Iterates the @audio. Iterating means discarding the first @n_samples
168 * samples of the audio stream.
170 * Returns: maximum number of remaining frames. If G_MAXUINT is returned,
171 * then the number of frames isn't known yet.
173 gsize
174 swfdec_audio_iterate (SwfdecAudio *audio, gsize n_samples)
176 SwfdecAudioClass *klass;
178 g_return_val_if_fail (SWFDEC_IS_AUDIO (audio), 0);
179 g_return_val_if_fail (n_samples > 0, 0);
181 klass = SWFDEC_AUDIO_GET_CLASS (audio);
182 g_assert (klass->iterate);
183 return klass->iterate (audio, n_samples);
186 void
187 swfdec_audio_set_actor (SwfdecAudio *audio, SwfdecActor *actor)
189 g_return_if_fail (SWFDEC_IS_AUDIO (audio));
190 g_return_if_fail (audio->player != NULL);
191 g_return_if_fail (actor == NULL || SWFDEC_IS_ACTOR (actor));
193 if (actor) {
194 g_object_ref (actor);
196 if (audio->actor) {
197 g_object_unref (audio->actor);
199 audio->actor = actor;
200 swfdec_audio_set_matrix (audio, actor ? &actor->sound_matrix : NULL);
203 void
204 swfdec_audio_set_matrix (SwfdecAudio *audio, const SwfdecSoundMatrix *matrix)
206 g_return_if_fail (SWFDEC_IS_AUDIO (audio));
208 audio->matrix = matrix;
211 /* FIXME: This function is pretty much a polling approach at sound matrix
212 * handling and it would be much nicer if we had a "changed" signal on the
213 * matrices. But matrices can't emit signals...
215 void
216 swfdec_audio_update_matrix (SwfdecAudio *audio)
218 SwfdecSoundMatrix sound;
220 g_return_if_fail (SWFDEC_IS_AUDIO (audio));
222 if (audio->matrix) {
223 swfdec_sound_matrix_multiply (&sound, audio->matrix,
224 &audio->player->priv->sound_matrix);
225 } else if (audio->player) {
226 sound = audio->player->priv->sound_matrix;
228 if (swfdec_sound_matrix_is_equal (&sound, &audio->matrix_cache))
229 return;
231 audio->matrix_cache = sound;
232 g_signal_emit (audio, signals[CHANGED], 0);
236 * swfdec_audio_render:
237 * @audio: a #SwfdecAudio
238 * @dest: memory area to render to
239 * @start_offset: offset in samples at which to start rendering. The offset is
240 * calculated relative to the last iteration, so the value set
241 * by swfdec_player_set_audio_advance() is ignored.
242 * @n_samples: amount of samples to render.
244 * Renders the samples from @audio into the area pointed to by @dest. Existing
245 * data in @dest is overwritten.
247 * Returns: The amount of samples actually rendered. Usually this number is
248 * equal to @n_samples, but if you arrived at the end of stream or the
249 * stream is still loading, this number may be lower. It indicates
250 * that no more samples are available.
252 gsize
253 swfdec_audio_render (SwfdecAudio *audio, gint16 *dest,
254 gsize start_offset, gsize n_samples)
256 SwfdecAudioClass *klass;
257 guint rendered;
259 g_return_val_if_fail (SWFDEC_IS_AUDIO (audio), 0);
260 g_return_val_if_fail (dest != NULL, 0);
261 g_return_val_if_fail (n_samples > 0, 0);
263 klass = SWFDEC_AUDIO_GET_CLASS (audio);
264 rendered = klass->render (audio, dest, start_offset, n_samples);
265 swfdec_sound_matrix_apply (&audio->matrix_cache, dest, rendered);
267 return rendered;
270 /*** SWFDEC_AUDIO_FORMAT ***/
272 /* SwfdecAudioFormat is represented in the least significant bits of a uint:
273 * - the LSBit is 1 if it's 16bit audio, 0 for 8bit
274 * - the next bit is 1 for stereo, 0 for mono
275 * - the other two bits are for the rate, see swfdec_audio_format_new()
276 * This is the same format the Flash file format uses to store audio formats.
279 SwfdecAudioFormat
280 swfdec_audio_format_parse (SwfdecBits *bits)
282 g_return_val_if_fail (bits != NULL, 0);
284 return swfdec_bits_getbits (bits, 4);
287 SwfdecAudioFormat
288 swfdec_audio_format_new (guint rate, guint channels, gboolean is_16bit)
290 SwfdecAudioFormat ret;
292 g_return_val_if_fail (channels == 1 || channels == 2, 0);
294 switch (rate) {
295 case 44100:
296 ret = 3 << 2;
297 break;
298 case 22050:
299 ret = 2 << 2;
300 break;
301 case 11025:
302 ret = 1 << 2;
303 break;
304 case 5512:
305 ret = 0 << 2;
306 break;
307 default:
308 g_return_val_if_reached (0);
309 break;
311 if (is_16bit)
312 ret |= 2;
313 if (channels == 2)
314 ret |= 1;
316 return ret;
319 guint
320 swfdec_audio_format_get_channels (SwfdecAudioFormat format)
322 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format), 2);
324 return (format & 0x1) + 1;
327 gboolean
328 swfdec_audio_format_is_16bit (SwfdecAudioFormat format)
330 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format), TRUE);
332 return format & 0x2 ? TRUE : FALSE;
335 guint
336 swfdec_audio_format_get_rate (SwfdecAudioFormat format)
338 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format), 44100);
340 return 44100 / swfdec_audio_format_get_granularity (format);
344 * swfdec_audio_format_get_granularity:
345 * @format: an auio format
347 * The granularity is a Swfdec-specific name, describing how often a sample in
348 * a 44100Hz audio stream is defined. So for example 44100Hz has a granularity
349 * of 1 and 11025Hz has a granularity of 4 (because only every fourth sample
350 * is defined).
352 * Returns: the granularity of the format
354 guint
355 swfdec_audio_format_get_granularity (SwfdecAudioFormat format)
357 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format), 1);
359 return 1 << (3 - (format >> 2));
362 const char *
363 swfdec_audio_format_to_string (SwfdecAudioFormat format)
365 static const char *names[] = {
366 "8bit 5.5kHz mono",
367 "8bit 5.5kHz stereo",
368 "16bit 5.5kHz mono",
369 "16bit 5.5kHz stereo",
370 "8bit 11kHz mono",
371 "8bit 11kHz stereo",
372 "16bit 11kHz mono",
373 "16bit 11kHz stereo",
374 "8bit 22kHz mono",
375 "8bit 22kHz stereo",
376 "16bit 22kHz mono",
377 "16bit 22kHz stereo",
378 "8bit 44kHz mono",
379 "8bit 44kHz stereo",
380 "16bit 44kHz mono",
381 "16bit 44kHz stereo"
383 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format), "");
385 return names[format];
389 * swfdec_audio_format_get_bytes_per_sample:
390 * @format: audio format to check
392 * Computes the number of bytes required to store one sample of audio encoded
393 * in @format.
395 * Returns: The number of bytes for one sample
397 guint
398 swfdec_audio_format_get_bytes_per_sample (SwfdecAudioFormat format)
400 guint bps[4] = { 1, 2, 2, 4 };
402 g_return_val_if_fail (SWFDEC_IS_AUDIO_FORMAT (format), 1);
404 return bps [format & 0x3];