~ubuntu-branches/ubuntu/saucy/gnash/saucy-proposed

« back to all changes in this revision

Viewing changes to server/asobj/SoundMad.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Sack
  • Date: 2008-10-13 14:29:49 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20081013142949-f6qdvnu4mn05ltdc
Tags: 0.8.4~~bzr9980-0ubuntu1
* new upstream release 0.8.4 (LP: #240325)
* ship new lib usr/lib/gnash/libmozsdk.so.* in mozilla-plugin-gnash
  - update debian/mozilla-plugin-gnash.install
* ship new lib usr/lib/gnash/libgnashnet.so.* in gnash-common
  - update debian/gnash-common.install
* add basic debian/build_head script to build latest CVS head packages.
  - add debian/build_head
* new sound architecture requires build depend on libsdl1.2-dev
  - update debian/control
* head build script now has been completely migrated to bzr (upstream +
  ubuntu)
  - update debian/build_head
* disable kde gui until klash/qt4 has been fixed; keep kde packages as empty
  packages for now.
  - update debian/rules
  - debian/klash.install
  - debian/klash.links
  - debian/klash.manpages
  - debian/konqueror-plugin-gnash.install
* drop libkonq5-dev build dependency accordingly
  - update debian/control
* don't install headers manually anymore. gnash doesnt provide a -dev
  package after all
  - update debian/rules
* update libs installed in gnash-common; libgnashserver-*.so is not available
  anymore (removed); in turn we add the new libgnashcore-*.so
  - update debian/gnash-common.install
* use -Os for optimization and properly pass CXXFLAGS=$(CFLAGS) to configure
  - update debian/rules
* touch firefox .autoreg in postinst of mozilla plugin
  - update debian/mozilla-plugin-gnash.postinst
* link gnash in ubufox plugins directory for the plugin alternative switcher
  - add debian/mozilla-plugin-gnash.links
* suggest ubufox accordingly
  - update debian/control
* add new required build-depends on libgif-dev
  - update debian/control
* add Xb-Npp-Description and Xb-Npp-File as new plugin database meta data
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// SoundMad.cpp:  Play sounds using libmad (MP3 audio decoder), for Gnash.
2
 
// 
3
 
//   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4
 
//
5
 
// This program is free software; you can redistribute it and/or modify
6
 
// it under the terms of the GNU General Public License as published by
7
 
// the Free Software Foundation; either version 3 of the License, or
8
 
// (at your option) any later version.
9
 
//
10
 
// This program is distributed in the hope that it will be useful,
11
 
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
// GNU General Public License for more details.
14
 
//
15
 
// You should have received a copy of the GNU General Public License
16
 
// along with this program; if not, write to the Free Software
17
 
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 
//
19
 
 
20
 
#ifdef HAVE_CONFIG_H
21
 
#include "gnashconfig.h"
22
 
#endif
23
 
 
24
 
#include "log.h"
25
 
#include "SoundMad.h"
26
 
#include "sound_definition.h" // for sound_sample
27
 
#include "movie_definition.h"
28
 
#include "sprite_instance.h"
29
 
#include "fn_call.h"
30
 
#include "GnashException.h"
31
 
#include "builtin_function.h"
32
 
#include "utility.h" // for convert_raw_data
33
 
 
34
 
#include <string>
35
 
 
36
 
namespace gnash {
37
 
 
38
 
int 
39
 
SoundMad::readPacket(boost::uint8_t* buf, int buf_size)
40
 
{
41
 
 
42
 
        size_t ret = connection->read(static_cast<void*>(buf), buf_size);
43
 
        inputPos += ret;
44
 
        return ret;
45
 
 
46
 
}
47
 
 
48
 
int 
49
 
SoundMad::seekMedia(int offset, int whence){
50
 
 
51
 
        // Offset is absolute new position in the file
52
 
        if (whence == SEEK_SET) {
53
 
                connection->seek(offset);
54
 
                inputPos = offset;
55
 
 
56
 
        // New position is offset + old position
57
 
        } else if (whence == SEEK_CUR) {
58
 
                connection->seek(inputPos + offset);
59
 
                inputPos = inputPos + offset;
60
 
 
61
 
        //      // New position is offset + end of file
62
 
        } else if (whence == SEEK_END) {
63
 
                // This is (most likely) a streamed file, so we can't seek to the end!
64
 
                // Instead we seek to 50.000 bytes... seems to work fine...
65
 
                connection->seek(50000);
66
 
                inputPos = 50000;
67
 
                
68
 
        }
69
 
 
70
 
        return inputPos;
71
 
}
72
 
 
73
 
 
74
 
void
75
 
SoundMad::setupDecoder(SoundMad* so)
76
 
{
77
 
 
78
 
        boost::intrusive_ptr<NetConnection> nc = so->connection;
79
 
        assert(nc);
80
 
 
81
 
        // Pass stuff from/to the NetConnection object.
82
 
        assert(so);
83
 
        if ( !nc->openConnection(so->externalURL) ) {
84
 
                log_error(_("Gnash could not open audio url: %s"), so->externalURL.c_str());
85
 
                delete so->lock;
86
 
                return;
87
 
        }
88
 
 
89
 
        so->inputPos = 0;
90
 
 
91
 
        // Init the mad decoder
92
 
        mad_stream_init(&so->stream);
93
 
        mad_frame_init(&so->frame);
94
 
        mad_synth_init(&so->synth);
95
 
 
96
 
        // Decode a single frame to decode the header
97
 
 
98
 
        // Fetch data from the file
99
 
        so->seekMedia(0, SEEK_SET);
100
 
        boost::uint8_t* buf = new boost::uint8_t[1024];
101
 
        int bufSize = so->readPacket(buf, 1024);
102
 
 
103
 
        // Setup the mad decoder
104
 
        mad_stream_buffer(&so->stream, buf, bufSize);
105
 
 
106
 
        int ret;
107
 
 
108
 
        int loops = 0;
109
 
        while(true) {
110
 
 
111
 
                ret = mad_frame_decode(&so->frame, &so->stream);
112
 
                loops++;
113
 
                
114
 
                // There is always some junk in front of the data, 
115
 
                // so we continue until we get past it.
116
 
                if (ret && so->stream.error == MAD_ERROR_LOSTSYNC) continue;
117
 
                
118
 
                // Error handling is done by relooping (max. 8 times) and just hooping that it will work...
119
 
                if (loops > 8) break;
120
 
                if (ret == -1 && so->stream.error != MAD_ERROR_BUFLEN && MAD_RECOVERABLE(so->stream.error)) {
121
 
                        log_error(_("Recoverable error while decoding MP3, MAD error: %s"), mad_stream_errorstr (&so->stream));
122
 
                        continue;
123
 
                }
124
 
                break;
125
 
        }
126
 
        so->bitrate = so->frame.header.bitrate;
127
 
 
128
 
        so->seekMedia(0, SEEK_SET);
129
 
        delete [] buf;
130
 
 
131
 
        // By deleting this lock we allow start() to start playback
132
 
        delete so->lock;
133
 
        return;
134
 
}
135
 
 
136
 
// audio callback is running in sound handler thread
137
 
bool SoundMad::getAudio(void* owner, boost::uint8_t* stream, int len)
138
 
{
139
 
        SoundMad* so = static_cast<SoundMad*>(owner);
140
 
 
141
 
        unsigned int pos = 0;
142
 
 
143
 
        // First use the data left over from last time
144
 
        if (so->leftOverSize > 0) {
145
 
 
146
 
                // If we have enough "leftover" data to fill the buffer,
147
 
                // we don't bother to decode some new.
148
 
                if (so->leftOverSize >= len) {
149
 
                        memcpy(stream, so->leftOverData, len);
150
 
                        int rest = so->leftOverSize - len;
151
 
                        if (rest < 1) {
152
 
                                delete[] so->leftOverData;
153
 
                                so->leftOverSize = 0;
154
 
                        } else {
155
 
                                boost::uint8_t* buf = new boost::uint8_t[rest];
156
 
                                memcpy(stream, so->leftOverData+len, rest);
157
 
                                delete[] so->leftOverData;
158
 
                                so->leftOverData = buf;
159
 
                                so->leftOverSize -= len;
160
 
                        }       
161
 
                        return true;
162
 
                } else {
163
 
                        memcpy(stream, so->leftOverData, so->leftOverSize);
164
 
                        pos += so->leftOverSize;
165
 
                        so->leftOverSize = 0;
166
 
                        delete[] so->leftOverData;
167
 
                }
168
 
        }
169
 
 
170
 
        boost::uint8_t* buf = new boost::uint8_t[8192];
171
 
        int bufSize = so->readPacket(buf, 8192);
172
 
        int orgBufSize = bufSize;
173
 
 
174
 
        bool loop = true;
175
 
        boost::uint8_t* ptr = new boost::uint8_t[8192];
176
 
 
177
 
        bool ret = true;
178
 
        media::sound_handler* s = get_sound_handler();
179
 
        if (bufSize > 0) {
180
 
                if (s) {
181
 
                        // temp raw buffer
182
 
                        boost::uint8_t* tmp_raw_buffer;
183
 
                        unsigned int tmp_raw_buffer_size;
184
 
                        int outsize = 0;
185
 
                        while (loop) {
186
 
                        // Decode audio
187
 
 
188
 
                                // Setup the mad decoder
189
 
                                mad_stream_buffer(&so->stream, buf+(orgBufSize-bufSize), bufSize);
190
 
 
191
 
                                int ret;
192
 
                                const unsigned char* old_next_frame = so->stream.next_frame;
193
 
                                int loops = 0;
194
 
                                while(true) {
195
 
 
196
 
                                        ret = mad_frame_decode(&so->frame, &so->stream);
197
 
                                        loops++;
198
 
                                        
199
 
                                        // There is always some junk in front of the data, 
200
 
                                        // so we continue until we get past it.
201
 
                                        if (ret && so->stream.error == MAD_ERROR_LOSTSYNC) continue;
202
 
                                        
203
 
                                        // Error handling is done by relooping (max. 8 times) and just hooping that it will work...
204
 
                                        if (loops > 8) break;
205
 
                                        if (ret == -1 && so->stream.error != MAD_ERROR_BUFLEN && MAD_RECOVERABLE(so->stream.error)) {
206
 
                                                log_error(_("Recoverable error while decoding MP3, MAD error: %s"), mad_stream_errorstr (&so->stream));
207
 
                                                continue;
208
 
                                        }
209
 
                                        
210
 
                                        break;
211
 
                                }
212
 
 
213
 
                                if (ret == -1 && so->stream.error != MAD_ERROR_BUFLEN) {
214
 
                                        log_error(_("Unrecoverable error while decoding MP3, MAD error: %s"), mad_stream_errorstr (&so->stream));
215
 
                                        bufSize = 0;
216
 
                                        loop = false;
217
 
                                } else if (ret == -1 && so->stream.error == MAD_ERROR_BUFLEN) {
218
 
                                        // the buffer is empty, no more to decode!
219
 
                                        bufSize = 0;
220
 
                                        loop = false;
221
 
                                } else {
222
 
                                        bufSize -= so->stream.next_frame - old_next_frame;
223
 
                                }
224
 
 
225
 
                                mad_synth_frame (&so->synth, &so->frame);
226
 
                                
227
 
                                outsize = so->synth.pcm.length * ((so->frame.header.mode) ? 4 : 2);
228
 
 
229
 
                                tmp_raw_buffer = new boost::uint8_t[outsize];
230
 
                                int sample;
231
 
                                
232
 
                                boost::int16_t* dst = reinterpret_cast<boost::int16_t*>(tmp_raw_buffer);
233
 
 
234
 
                                // transfer the decoded samples into the sound-struct, and do some
235
 
                                // scaling while we're at it.
236
 
                                for(int f = 0; f < so->synth.pcm.length; f++)
237
 
                                {
238
 
                                        for (int e = 0; e < ((so->frame.header.mode) ? 2 : 1); e++){ // channels (stereo/mono)
239
 
 
240
 
                                                mad_fixed_t mad_sample = so->synth.pcm.samples[e][f];
241
 
 
242
 
                                                // round
243
 
                                                mad_sample += (1L << (MAD_F_FRACBITS - 16));
244
 
 
245
 
                                                // clip
246
 
                                                if (mad_sample >= MAD_F_ONE) mad_sample = MAD_F_ONE - 1;
247
 
                                                else if (mad_sample < -MAD_F_ONE) mad_sample = -MAD_F_ONE;
248
 
 
249
 
                                                // quantize
250
 
                                                sample = mad_sample >> (MAD_F_FRACBITS + 1 - 16);
251
 
 
252
 
                                                if ( sample != static_cast<boost::int16_t>(sample) ) sample = sample < 0 ? -32768 : 32767;
253
 
 
254
 
                                                *dst++ = sample;
255
 
                                        }
256
 
                                }
257
 
 
258
 
                                // If we need to convert samplerate or/and from mono to stereo...
259
 
                                if (outsize > 0 && (so->frame.header.samplerate != 44100 || !so->frame.header.mode)) {
260
 
 
261
 
                                        boost::int16_t* adjusted_data = 0;
262
 
                                        int     adjusted_size = 0;
263
 
                                        int sample_count = outsize / ((so->frame.header.mode) ? 4 : 2);
264
 
 
265
 
                                        // Convert to needed samplerate
266
 
                                        convert_raw_data(&adjusted_data, &adjusted_size, tmp_raw_buffer, sample_count, 2, 
267
 
                                                        so->frame.header.samplerate, so->frame.header.mode,
268
 
                                                        44100, true/*stereo*/);
269
 
 
270
 
                                        // Hopefully this won't happen
271
 
                                        if (!adjusted_data) {
272
 
                                                log_error(_("Error in sound sample convertion"));
273
 
                                                continue;
274
 
                                        }
275
 
 
276
 
                                        // Move the new data to the sound-struct
277
 
                                        delete[] tmp_raw_buffer;
278
 
                                        tmp_raw_buffer = reinterpret_cast<boost::uint8_t*>(adjusted_data);
279
 
                                        tmp_raw_buffer_size = adjusted_size;
280
 
 
281
 
                                } else {
282
 
                                        tmp_raw_buffer_size = outsize;
283
 
                                }
284
 
 
285
 
 
286
 
 
287
 
 
288
 
                                // Copy the data to buffer
289
 
                                // If the decoded data isn't enough to fill the buffer, we put the decoded
290
 
                                // data into the buffer, and continues decoding.
291
 
                                if (tmp_raw_buffer_size <= len-pos) {
292
 
                                        memcpy(stream+pos, tmp_raw_buffer, tmp_raw_buffer_size);
293
 
                                        pos += tmp_raw_buffer_size;
294
 
                                } else {
295
 
                                // If we can fill the buffer, and still have "leftovers", we save them
296
 
                                // and use them later.
297
 
                                        int rest = len-pos;
298
 
                                        so->leftOverSize = tmp_raw_buffer_size - rest;
299
 
                                        memcpy(stream+pos, tmp_raw_buffer, rest);
300
 
                                        so->leftOverData = new boost::uint8_t[so->leftOverSize];
301
 
                                        memcpy(so->leftOverData, (tmp_raw_buffer)+rest, so->leftOverSize);
302
 
                                        loop = false;
303
 
                                        pos += rest;
304
 
                                }
305
 
                                delete[] tmp_raw_buffer;
306
 
                        } // while               
307
 
                } // (s) 
308
 
        } else { // bufSize > 0
309
 
                // If we should loop we make sure we do.
310
 
                if (so->remainingLoops != 0) {
311
 
                        so->remainingLoops--;
312
 
 
313
 
                        // Seek to begining of file
314
 
                        so->seekMedia(0, SEEK_SET);
315
 
                } else {
316
 
                         // Stops playback by returning false which makes the soundhandler
317
 
                         // detach this sound.
318
 
                         ret = false;
319
 
                         so->isAttached = false;
320
 
                }
321
 
        }
322
 
        so->seekMedia(-bufSize, SEEK_CUR);
323
 
        delete[] ptr;
324
 
        return ret;
325
 
}
326
 
 
327
 
SoundMad::~SoundMad() {
328
 
        if (leftOverData && leftOverSize) delete[] leftOverData;
329
 
 
330
 
        if (isAttached) {
331
 
                mad_synth_finish(&synth);
332
 
                mad_frame_finish(&frame);
333
 
                mad_stream_finish(&stream);
334
 
 
335
 
                media::sound_handler* s = get_sound_handler();
336
 
                if (s) {
337
 
                        s->detach_aux_streamer(this);
338
 
                }
339
 
        }
340
 
 
341
 
}
342
 
 
343
 
void
344
 
SoundMad::loadSound(std::string file, bool streaming)
345
 
{
346
 
        leftOverData = NULL;
347
 
        leftOverSize = 0;
348
 
        remainingLoops = 0;
349
 
 
350
 
        if (connection) {
351
 
                log_error(_("This sound already has a connection?  (We try to handle this by overriding the old one...)"));
352
 
        }
353
 
        externalURL = file;
354
 
 
355
 
        connection = new NetConnection();
356
 
 
357
 
        externalSound = true;
358
 
        isStreaming = streaming;
359
 
 
360
 
        lock = new boost::mutex::scoped_lock(setupMutex);
361
 
 
362
 
        // To avoid blocking while connecting, we use a thread.
363
 
        setupThread = new boost::thread(boost::bind(SoundMad::setupDecoder, this));
364
 
 
365
 
}
366
 
 
367
 
void
368
 
SoundMad::start(int offset, int loops)
369
 
{
370
 
        boost::mutex::scoped_lock lock(setupMutex);
371
 
 
372
 
        if (externalSound) {
373
 
                seekMedia((bitrate*offset)/8, SEEK_SET);
374
 
 
375
 
                // Save how many loops to do
376
 
                if (loops > 0) {
377
 
                        remainingLoops = loops;
378
 
                }
379
 
        }
380
 
 
381
 
        // Start sound
382
 
        media::sound_handler* s = get_sound_handler();
383
 
        if (s) {
384
 
                if (externalSound) {
385
 
                        if (1)
386
 
                        {
387
 
                                s->attach_aux_streamer(getAudio, (void*) this);
388
 
                                isAttached = true;
389
 
                        } 
390
 
                } else {
391
 
                s->play_sound(soundId, loops, offset, 0, NULL);
392
 
            }
393
 
        }
394
 
}
395
 
 
396
 
void
397
 
SoundMad::stop(int si)
398
 
{
399
 
        // stop the sound
400
 
        media::sound_handler* s = get_sound_handler();
401
 
        if (s != NULL)
402
 
        {
403
 
            if (si < 0) {
404
 
                if (externalSound) {
405
 
                        s->detach_aux_streamer(this);
406
 
                } else {
407
 
                                s->stop_sound(soundId);
408
 
                        }
409
 
                } else {
410
 
                        s->stop_sound(si);
411
 
                }
412
 
        }
413
 
}
414
 
 
415
 
unsigned int
416
 
SoundMad::getDuration()
417
 
{
418
 
        // If this is a event sound get the info from the soundhandler
419
 
        if (!externalSound) {
420
 
                media::sound_handler* s = get_sound_handler();
421
 
                if (s) {                
422
 
                return (s->get_duration(soundId));
423
 
            } else {
424
 
                return 0; // just in case
425
 
                }
426
 
        }
427
 
 
428
 
        // Return the duration of the file in milliseconds
429
 
/*      if (formatCtx && audioIndex) {
430
 
                return static_cast<unsigned int>(formatCtx->duration * 1000);
431
 
        } else {
432
 
                return 0;
433
 
        }*/
434
 
        return 0;
435
 
}
436
 
 
437
 
unsigned int
438
 
SoundMad::getPosition()
439
 
{
440
 
 
441
 
        // If this is a event sound get the info from the soundhandler
442
 
        if (!externalSound) {
443
 
                media::sound_handler* s = get_sound_handler();
444
 
                if (s) {
445
 
                        return s->get_position(soundId);        
446
 
            } else {
447
 
                return 0; // just in case
448
 
                }
449
 
        }
450
 
 
451
 
        // Return the position in the file in milliseconds
452
 
        return inputPos/bitrate/8*1000;
453
 
}
454
 
 
455
 
} // end of gnash namespace