~ubuntu-branches/ubuntu/hoary/kdemultimedia/hoary

« back to all changes in this revision

Viewing changes to mpg123_artsplugin/mpg123PlayObject_impl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Martin Schulze
  • Date: 2003-01-22 15:00:51 UTC
  • Revision ID: james.westby@ubuntu.com-20030122150051-uihwkdoxf15mi1tn
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: mpg123PlayObject_impl.cpp,v 1.22.2.1 2001/08/23 18:05:46 waba Exp $
 
3
 * Copyright (C) 2001 Kevin Puetz
 
4
 *
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program 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
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 *
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
#include <sys/types.h>
 
24
#include <sys/ipc.h>
 
25
#include <sys/sem.h>
 
26
#include <sys/stat.h>
 
27
#include <sys/shm.h>
 
28
#include <sys/wait.h>
 
29
 
 
30
#include <assert.h>
 
31
#include <errno.h>
 
32
#include <fcntl.h>
 
33
#include <math.h>
 
34
#include <signal.h>
 
35
#include <stdio.h>
 
36
#include <stdlib.h>
 
37
#include <string.h>
 
38
 
 
39
/////////////////////////////////////////////////////////////
 
40
// aRts interface
 
41
 
 
42
#include <stdsynthmodule.h>
 
43
#include "mpg123arts.h"
 
44
#include <convert.h>
 
45
#include <debug.h>
 
46
 
 
47
 
 
48
#include "mpg123PlayObject_impl.h"
 
49
 
 
50
using namespace Arts;
 
51
 
 
52
int mpg123PlayObject_impl::decoder_init = 0;
 
53
 
 
54
// This is to minimize the hackery in mpg123
 
55
int audio_get_formats(struct audio_info_struct *)
 
56
{
 
57
        return AUDIO_FORMAT_SIGNED_16;
 
58
}
 
59
 
 
60
// This is purely convenience
 
61
void mpg123PlayObject_impl::set_synth_functions(struct frame *fr)
 
62
{
 
63
        typedef int (*func)(real *,int,unsigned char *,int *);
 
64
        typedef int (*func_mono)(real *,unsigned char *,int *);
 
65
        typedef void (*func_dct36)(real *,real *,real *,real *,real *);
 
66
 
 
67
        int ds = fr->down_sample;
 
68
        int p8=0;
 
69
        // it's as big as pcmdata (internal to mpg123 - where this size comes from I dunno
 
70
        // but it'll be big enough, since all data comes as memcpy's from there.
 
71
 
 
72
        static func funcs[][4] = { 
 
73
                { synth_1to1,
 
74
                  synth_2to1,
 
75
                  synth_4to1,
 
76
                  synth_ntom } ,
 
77
                { synth_1to1_8bit,
 
78
                  synth_2to1_8bit,
 
79
                  synth_4to1_8bit,
 
80
                  synth_ntom_8bit } 
 
81
#ifdef USE_3DNOW
 
82
                ,{synth_1to1_3dnow,
 
83
                  synth_2to1,
 
84
                  synth_4to1,
 
85
                  synth_ntom }
 
86
#endif 
 
87
        };
 
88
 
 
89
        static func_mono funcs_mono[2][2][4] = {    
 
90
                { { synth_1to1_mono2stereo ,
 
91
                    synth_2to1_mono2stereo ,
 
92
                    synth_4to1_mono2stereo ,
 
93
                    synth_ntom_mono2stereo } ,
 
94
                  { synth_1to1_8bit_mono2stereo ,
 
95
                    synth_2to1_8bit_mono2stereo ,
 
96
                    synth_4to1_8bit_mono2stereo ,
 
97
                    synth_ntom_8bit_mono2stereo } } ,
 
98
                { { synth_1to1_mono ,
 
99
                    synth_2to1_mono ,
 
100
                    synth_4to1_mono ,
 
101
                    synth_ntom_mono } ,
 
102
                  { synth_1to1_8bit_mono ,
 
103
                    synth_2to1_8bit_mono ,
 
104
                    synth_4to1_8bit_mono ,
 
105
                    synth_ntom_8bit_mono } }
 
106
        };
 
107
 
 
108
#ifdef USE_3DNOW      
 
109
        static func_dct36 funcs_dct36[2] = {dct36 , dct36_3dnow};
 
110
#endif
 
111
 
 
112
        if (0) // ((ai.format & AUDIO_FORMAT_MASK) == AUDIO_FORMAT_8)
 
113
                p8 = 1;
 
114
        fr->synth = funcs[p8][ds];
 
115
        fr->synth_mono = funcs_mono[param.force_stereo?0:1][p8][ds];
 
116
 
 
117
#ifdef USE_3DNOW
 
118
        arts_debug("set_synth_functions: 3dnow?");
 
119
        /* check cpuflags bit 31 (3DNow!) and 23 (MMX) */
 
120
        if((param.stat_3dnow < 2) && 
 
121
                ((param.stat_3dnow == 1) ||
 
122
                (getcpuflags() & 0x80800000) == 0x80800000)) 
 
123
        {
 
124
                fr->synth = funcs[2][ds]; /* 3DNow! optimized synth_1to1() */
 
125
                        fr->dct36 = funcs_dct36[1]; /* 3DNow! optimized dct36() */
 
126
        } else {
 
127
                fr->dct36 = funcs_dct36[0];
 
128
        }
 
129
#endif
 
130
 
 
131
        if (p8) 
 
132
        {
 
133
                make_conv16to8_table(-1); // FIX
 
134
        }
 
135
}
 
136
 
 
137
void mpg123PlayObject_impl::initialise_decoder()
 
138
{
 
139
        arts_debug("initializing decoder");
 
140
        set_synth_functions(&mp->fr);
 
141
        make_decode_tables(param.outscale);
 
142
        init_layer2();  // inits also shared tables with layer1
 
143
        init_layer3(mp->fr.down_sample);        // No down sample support (yet?)
 
144
}
 
145
 
 
146
int mpg123PlayObject_impl::play_frame(int init) 
 
147
{
 
148
        struct frame *fr = &mp->fr;
 
149
        int clip;
 
150
        long newrate;
 
151
        long old_rate,old_format,old_channels;
 
152
 
 
153
        if(fr->header_change || init) {
 
154
 
 
155
                if(fr->header_change > 1 || init) {
 
156
                        old_rate = ai.rate;
 
157
                        old_format = ai.format;
 
158
                        old_channels = ai.channels;
 
159
 
 
160
                        newrate = (long)param.pitch * (freqs[fr->sampling_frequency]>>(param.down_sample));
 
161
                        if(param.verbose && param.pitch != 1.0)
 
162
                                fprintf(stderr,"Pitching to %f => %ld Hz\n",param.pitch,newrate);   
 
163
 
 
164
                        fr->down_sample = param.down_sample;
 
165
 
 
166
                        ai.format = AUDIO_FORMAT_SIGNED_16;
 
167
                        ai.rate = 44100;
 
168
                        ai.channels = 2;
 
169
 
 
170
                        /* check, whether the fitter setted our proposed rate */
 
171
                        if(ai.rate != newrate) {
 
172
                                arts_debug("resampling from %d to %d",newrate, ai.rate);
 
173
                                if(ai.rate == (newrate>>1) )
 
174
                                        fr->down_sample++;
 
175
                                else if(ai.rate == (newrate>>2) )
 
176
                                        fr->down_sample+=2;
 
177
                                else {
 
178
                                        fr->down_sample = 3;
 
179
                                        fprintf(stderr,"Warning, flexible rate not heavily tested!\n");
 
180
                                }
 
181
                                if(fr->down_sample > 3)
 
182
                                        fr->down_sample = 3;
 
183
                        }
 
184
 
 
185
                        if(fr->down_sample > 3)
 
186
                                fr->down_sample = 3;
 
187
 
 
188
                        switch(fr->down_sample) {
 
189
                                case 0:
 
190
                                case 1:
 
191
                                case 2:
 
192
                                        fr->down_sample_sblimit = SBLIMIT>>(fr->down_sample);
 
193
                                        break;
 
194
                                case 3:
 
195
                                        {
 
196
                                                long n = (long)param.pitch * freqs[fr->sampling_frequency];
 
197
                                                long m = ai.rate;
 
198
 
 
199
                                                synth_ntom_set_step(n,m);
 
200
 
 
201
                                                if(n>m) {
 
202
                                                        fr->down_sample_sblimit = SBLIMIT * m;
 
203
                                                        fr->down_sample_sblimit /= n;
 
204
                                                }
 
205
                                                else {
 
206
                                                        fr->down_sample_sblimit = SBLIMIT;
 
207
                                                }
 
208
                                        }
 
209
                                        break;
 
210
                        }
 
211
 
 
212
                        set_synth_functions(fr);
 
213
                        //init_output(); XXX: eh?
 
214
                        if(ai.rate != old_rate || ai.channels != old_channels ||
 
215
                                        ai.format != old_format || param.force_reopen) {
 
216
                                if(param.force_mono < 0) {
 
217
                                        if(ai.channels == 1)
 
218
                                                fr->single = 3;
 
219
                                        else
 
220
                                                fr->single = -1;
 
221
                                }
 
222
                        }
 
223
                        else
 
224
                                fr->single = param.force_mono;
 
225
 
 
226
                        param.force_stereo &= ~0x2;
 
227
                        if(fr->single >= 0 && ai.channels == 2) {
 
228
                                param.force_stereo |= 0x2;
 
229
                        }
 
230
 
 
231
                        set_synth_functions(fr);
 
232
                        init_layer3(fr->down_sample_sblimit);
 
233
                        //      reset_audio(); XXX: wha?
 
234
                        if(param.verbose) {
 
235
                                if(fr->down_sample == 3) {
 
236
                                        long n = (long)param.pitch * freqs[fr->sampling_frequency];
 
237
                                        long m = ai.rate;
 
238
                                        if(n > m) {
 
239
                                                fprintf(stderr,"Audio: %2.4f:1 conversion,",(float)n/(float)m);
 
240
                                        }
 
241
                                        else {
 
242
                                                fprintf(stderr,"Audio: 1:%2.4f conversion,",(float)m/(float)n);
 
243
                                        }
 
244
                                }
 
245
                                else {
 
246
                                        fprintf(stderr,"Audio: %ld:1 conversion,",(long)pow(2.0,fr->down_sample));
 
247
                                }
 
248
                                fprintf(stderr," rate: %ld, encoding: %s, channels: %d\n",ai.rate,audio_encoding_name(ai.format),ai.channels);
 
249
                        }
 
250
                }
 
251
        }
 
252
 
 
253
        if (fr->error_protection) {
 
254
                /* skip crc, we are byte aligned here */
 
255
                getbyte(&bsi);
 
256
                getbyte(&bsi);
 
257
        }
 
258
 
 
259
        /* do the decoding */
 
260
        switch(fr->lay) {
 
261
                case 1:
 
262
                        if( (clip=do_layer1(mp,fr,param.outmode,&ai)) < 0 )
 
263
                                return 0;
 
264
                        break;
 
265
                case 2:
 
266
                        if( (clip=do_layer2(mp,fr,param.outmode,&ai)) < 0 )
 
267
                                return 0;
 
268
                        break;
 
269
                case 3:
 
270
                        if( (clip=do_layer3(mp,fr,param.outmode,&ai)) < 0 )
 
271
                                return 0;
 
272
                        break;
 
273
                default:
 
274
                        clip = 0;
 
275
        }
 
276
 
 
277
        if(clip > 0 && param.checkrange)
 
278
                fprintf(stderr,"%d samples clipped\n", clip);
 
279
 
 
280
        return pcm_point / 4;
 
281
}
 
282
 
 
283
mpg123PlayObject_impl::mpg123PlayObject_impl()
 
284
{
 
285
        pcm_buf = new unsigned char[16384*2+1024*2];
 
286
        mp = (struct mpstr *)malloc(sizeof(struct mpstr));
 
287
        memset(mp, 0, sizeof(struct mpstr));
 
288
        //memset(&mp->fr, 0, sizeof(struct frame)); XXX: why would I need to do this?
 
289
 
 
290
        prgName = strdup("arts/mpg123");
 
291
        prgVersion = strdup("$Revision: 1.22.2.1 $");
 
292
        pcm_point = 0;
 
293
        pcm_sample=pcm_buf; // just point this to our internal buffer
 
294
        memset(&param, 0, sizeof(struct parameter));
 
295
        param.halfspeed = 0;
 
296
        param.outmode = DECODE_BUFFER+999;
 
297
        param.usebuffer = 0;
 
298
        param.down_sample = 0;
 
299
        param.force_stereo = 1; // XXX was 0
 
300
        param.force_mono = -1;
 
301
        param.pitch = 1.0;
 
302
        param.checkrange = 0;
 
303
        param.outscale = 32768;
 
304
        param.tryresync = 2;
 
305
        
 
306
        equalfile = NULL;
 
307
        struct shmid_ds bleh;
 
308
        shm_id = shmget(IPC_PRIVATE, sizeof(*shm_buf), 0600);
 
309
        shm_buf = (struct buf_t *)shmat(shm_id, 0, 0);
 
310
        // mark it to be destroyed after the last detach
 
311
        shmctl(shm_id, IPC_RMID, &bleh);
 
312
        // sem0 has base, sem1 remaining space,sem2 seekTo
 
313
        buflen_sem = semget(IPC_PRIVATE, 3, 0600);
 
314
        child_pid = 0;
 
315
}
 
316
 
 
317
mpg123PlayObject_impl::~mpg123PlayObject_impl()
 
318
{
 
319
        artsdebug("Destroying PlayObject");
 
320
        halt();
 
321
        union semun semdat;
 
322
        arts_debug("removing IPC resources");
 
323
        semctl(buflen_sem,0,IPC_RMID,semdat);
 
324
        // WABA: Don't remove the cast, it is needed on some platforms.
 
325
        shmdt((char *)shm_buf);
 
326
        delete pcm_buf;
 
327
}
 
328
 
 
329
bool mpg123PlayObject_impl::loadMedia(const string &filename)
 
330
{
 
331
//      string filename = "http://131.174.33.2:9024/";
 
332
        arts_debug("mpg123: loadMedia %s", filename.c_str());
 
333
        halt(); // stop playing any previous stream
 
334
        arts_debug("previous playback killed");
 
335
        struct sembuf semoper;
 
336
        union semun semdat;
 
337
 
 
338
        semoper.sem_flg = 0; // normal blocking semaphores
 
339
 
 
340
        semdat.val = 0;
 
341
        if(semctl(buflen_sem,0,SETVAL,semdat)) // no data in the queue 
 
342
                arts_debug("couldn't clear queue");
 
343
        semdat.val = 0;
 
344
        if(semctl(buflen_sem,2,SETVAL,semdat)) // seekTo is -1 (ie, no seek)
 
345
                arts_debug("couldn't clear seekTo");
 
346
        semdat.val = BACKBUFSIZ;
 
347
        if(semctl(buflen_sem,1,SETVAL,semdat)) // setup the starting free space
 
348
                arts_debug("couldn't mark buffer empty"); 
 
349
 
 
350
        buf_pos = 0;
 
351
 
 
352
        //throw off a process to handle the decoding
 
353
        if((child_pid = fork())) {
 
354
                return true; // all further setup happens in the child
 
355
        }
 
356
        arts_debug("child process");
 
357
        initialise_decoder();
 
358
 
 
359
        snprintf(param.filename, 250, filename.c_str());
 
360
        memset(&ai, 0, sizeof(struct audio_info_struct));
 
361
        mp->fr.sampling_frequency = 0;
 
362
        mp->fr.down_sample = 0;
 
363
        mp->fr.single = -1;
 
364
        mp->fr.down_sample_sblimit = SBLIMIT>>(mp->fr.down_sample);
 
365
        sample_freq = freqs[mp->fr.sampling_frequency]>>(param.down_sample);
 
366
 
 
367
        // audio_info_struct_init
 
368
        ai.rate = 44100;
 
369
        ai.gain = -1;
 
370
        ai.output = AUDIO_OUT_LINE_OUT;
 
371
        ai.device = 0;
 
372
        ai.channels = 2;
 
373
        ai.format = AUDIO_FORMAT_SIGNED_16;
 
374
        audio_capabilities(&ai);
 
375
 
 
376
        set_synth_functions(&mp->fr);
 
377
 
 
378
        if (rd)
 
379
                rd->close(rd);
 
380
        if (!open_stream(filename.c_str(), -1)) {
 
381
                printf("erorr opening stream\n");
 
382
                return 0;
 
383
        }
 
384
 
 
385
        mpeg_name[0] = 0;
 
386
        snprintf(mpeg_name, 1000, filename.c_str());    
 
387
        if (strstr(filename.c_str(), "http://") != NULL) {
 
388
                sprintf(mpeg_name, "ShoutCast from %s\n", filename.c_str());
 
389
                streaming = 1;
 
390
        }
 
391
 
 
392
        read_frame_init(&mp->fr);
 
393
 
 
394
        XHEADDATA xingHeader;
 
395
 
 
396
        shm_buf->pos = 0;
 
397
 
 
398
        read_frame(rd,&mp->fr); // read in a frame for the xing code to play with
 
399
        bool gotXing = false;
 
400
        if(!streaming) {
 
401
                gotXing = mpg123_stream_check_for_xing_header(&mp->fr,&xingHeader);
 
402
        if(gotXing) 
 
403
                shm_buf->len = xingHeader.frames;
 
404
        else // assume no VBR for non-Xing
 
405
                shm_buf->len = static_cast<unsigned long>(rd->filelen / compute_bpf(&mp->fr));
 
406
        } else {
 
407
                shm_buf->len = 1;
 
408
        }
 
409
        // can't calculate tpf until we reach a non-header frame
 
410
 
 
411
        int skipped = 0;
 
412
        if (sync_stream(rd, &mp->fr, 0xffff, &skipped) <= 0) {
 
413
                fprintf(stderr,"Can't find frame start");
 
414
                rd->close(rd);
 
415
                return 0;
 
416
        }
 
417
 
 
418
 
 
419
/*
 
420
        if (!mpeg_get_frame_info(filename.c_str())) {
 
421
                printf("mpeg_get_frame_info(%s) failed\n", filename.c_str());
 
422
                return 0;
 
423
        }
 
424
*/
 
425
        arts_debug("mpg123: loadMedia %s got %s", filename.c_str(), mpeg_name);
 
426
        
 
427
        short *decode_buf = reinterpret_cast<short *>(pcm_sample);
 
428
        bool init=true;
 
429
                do {
 
430
                        // get more data
 
431
 
 
432
                        int seekTo = semctl(buflen_sem, 2, GETVAL, semdat);
 
433
                        if (seekTo) { // we need to seek, to sync back up
 
434
                                unsigned long offset;
 
435
                                arts_debug("seeking to %d\n", seekTo);
 
436
                                if(gotXing && (xingHeader.flags & TOC_FLAG) && xingHeader.toc) // do we have a table of contents?
 
437
                                        offset = mpg123_seek_point(xingHeader.toc,rd->filelen,100 * (seekTo -1) / double(shm_buf->len)); // relative position in file
 
438
                                else
 
439
                                        offset = static_cast<unsigned long>(rd->filelen * ((seekTo-1) / double(shm_buf->len))); // the crude ole' fashioned way
 
440
                                rd->rewind(rd);
 
441
                                lseek(rd->filept, offset, SEEK_SET);
 
442
 
 
443
                                // now we need to sync back up :-)
 
444
                                read_frame(rd,&mp->fr); 
 
445
                                read_frame(rd,&mp->fr); 
 
446
                        //      if (sync_stream(rd, &mp->fr, 0xffff, &skipped) <= 0) {
 
447
                        //              arts_debug("Can't find frame start");
 
448
                //                      rd->close(rd);
 
449
                //                      break;
 
450
                //              }
 
451
                                shm_buf->pos = seekTo; // assume we got the frame we were after? I don't have a better idea...
 
452
                                semdat.val = 0;
 
453
                                semctl(buflen_sem, 2, SETVAL, semdat); // we've done it
 
454
                        }
 
455
 
 
456
                        if (!read_frame(rd,&mp->fr)) {
 
457
                                // mpg123 says we're done, or we errored (in which case we're done)
 
458
                                arts_debug("out of frames, exiting");
 
459
                                break;
 
460
                        }
 
461
 
 
462
                        if(init) // need to figure this one out with a real audio frame...
 
463
                        {       
 
464
                                arts_debug("samplerate: %d (%d)",mp->fr.sampling_frequency,freqs[mp->fr.sampling_frequency]>>(param.down_sample));
 
465
                                shm_buf->tpf = compute_tpf(&mp->fr);
 
466
                        }
 
467
                        int thisPass = play_frame(init);
 
468
                        if(init) // need to figure this one out with a real audio frame...
 
469
                                arts_debug("samplerate: %d",mp->fr.sampling_frequency);
 
470
                        init=false; // no longer init :-)
 
471
 
 
472
                        semoper.sem_num = 1;
 
473
                        semoper.sem_op = -thisPass; 
 
474
                        semop(buflen_sem, &semoper, 1);
 
475
 
 
476
                        // block until there's enough space to stick in this frame
 
477
                        int roomFor = semctl(buflen_sem, 1, GETVAL, semdat);
 
478
                        if (roomFor > BACKBUFSIZ) { 
 
479
                                arts_debug("exit requested (%d slots available), bye!",roomFor);
 
480
                                // this can never go above BACKBUFSIZ in normal operation, 
 
481
                                // the consumer wants us to exit
 
482
                                break;
 
483
                        }
 
484
 
 
485
                        //arts_debug("decoded %d frames (%d avail)",thisPass,roomFor);
 
486
                                
 
487
                        for(int i=0 ; i <thisPass ; 
 
488
                            ++i, buf_pos = ((buf_pos + 1) % BACKBUFSIZ)) {
 
489
                                shm_buf->left[buf_pos] = conv_16le_float(decode_buf[2*i]);
 
490
                                shm_buf->right[buf_pos] = conv_16le_float(decode_buf[2*i+1]);
 
491
                        }
 
492
                        shm_buf->pos++; // ran another frame through the mill
 
493
                        pcm_point=0;
 
494
                        //arts_debug("enqueued them");
 
495
                        semoper.sem_num = 0;
 
496
                        semoper.sem_op = thisPass; 
 
497
                        semop(buflen_sem,&semoper,1); // mark the additional data now available
 
498
 
 
499
                        //arts_debug("calculated %d more samples",shm_buf->backbuflen );
 
500
                } while(1);
 
501
 
 
502
                //signal completion
 
503
                semdat.val = 0;
 
504
                // no more data available
 
505
                semctl(buflen_sem, 0, SETVAL, semdat); 
 
506
                // and no room either (ie, none coming)
 
507
                semctl(buflen_sem, 1, SETVAL, semdat); 
 
508
 
 
509
                arts_debug("decoder process exiting");
 
510
                exit(0);
 
511
        return true;
 
512
}
 
513
 
 
514
string mpg123PlayObject_impl::description()
 
515
{
 
516
        return "mpg123 artsplug - w00t!";
 
517
}
 
518
 
 
519
//XXX
 
520
poTime mpg123PlayObject_impl::currentTime()
 
521
{
 
522
        return poTime(shm_buf->pos * shm_buf->tpf, 0, 0, "none");
 
523
}
 
524
 
 
525
//XXX
 
526
poTime mpg123PlayObject_impl::overallTime()
 
527
{
 
528
        return poTime(shm_buf->len * shm_buf->tpf, 0, 0, "none");
 
529
}
 
530
 
 
531
poCapabilities mpg123PlayObject_impl::capabilities()
 
532
{
 
533
        return static_cast<poCapabilities>(capPause | capSeek);
 
534
}
 
535
 
 
536
//YYY
 
537
string mpg123PlayObject_impl::mediaName()
 
538
{
 
539
        return "";
 
540
}
 
541
 
 
542
poState mpg123PlayObject_impl::state()
 
543
{
 
544
        return mState;
 
545
}
 
546
 
 
547
void mpg123PlayObject_impl::play()
 
548
{
 
549
        arts_debug("mpg123: play");
 
550
        mState = posPlaying;
 
551
}
 
552
 
 
553
void mpg123PlayObject_impl::halt()
 
554
{
 
555
        mState = posIdle;
 
556
        union semun semdat;
 
557
 
 
558
        if (child_pid) {
 
559
                arts_debug("killing decoder process");
 
560
                semdat.val = 2*BACKBUFSIZ;
 
561
                semctl(buflen_sem, 1, SETVAL, semdat); 
 
562
                waitpid(child_pid, NULL, 0);
 
563
                child_pid = 0;
 
564
        }
 
565
        // tell the producer to exit (would also result in us halting, if we weren't already)
 
566
 
 
567
        // mainly this is to ensure that the decoder wakes up to notice
 
568
}
 
569
 
 
570
//XXX disabled for now
 
571
void mpg123PlayObject_impl::seek(const class poTime &t)
 
572
{
 
573
        union semun foo;
 
574
 
 
575
        // this index is one-based so 0 can represent no seek
 
576
        foo.val = static_cast<int>(t.seconds / shm_buf->tpf + 1);
 
577
        arts_debug("requesting seek to %d", foo.val);
 
578
        semctl(buflen_sem, 2, SETVAL, foo); // we've done it
 
579
}
 
580
 
 
581
/* Pause implemented on the streaming-side - decoding will simply block on it's own */
 
582
void mpg123PlayObject_impl::pause()
 
583
{
 
584
        mState = posPaused;
 
585
}
 
586
 
 
587
/*
 
588
 * SynthModule interface
 
589
 * - where is stop? initialize?
 
590
 */
 
591
 
 
592
void mpg123PlayObject_impl::streamInit()
 
593
{
 
594
        arts_debug("streamInit");
 
595
}
 
596
 
 
597
void mpg123PlayObject_impl::streamStart()
 
598
{
 
599
        arts_debug("streamStart");
 
600
}
 
601
 
 
602
void mpg123PlayObject_impl::calculateBlock(unsigned long samples)
 
603
{
 
604
        int samplesAvailable = 0;
 
605
        
 
606
        //arts_debug("calculateBlock");
 
607
        
 
608
        if (mState==posPlaying) {
 
609
                //arts_debug("calculateBlock, %d(%d) of %d samples in buffer", 
 
610
                //shm_buf->buflen - bufpos, shm_buf->backbuflen,samples);
 
611
                        
 
612
                struct sembuf bleh;
 
613
                                
 
614
                bleh.sem_num = 0;
 
615
                bleh.sem_flg = IPC_NOWAIT;
 
616
                                                
 
617
                //arts_debug("%d samples wanted", samplesAvailable);
 
618
                bleh.sem_op = -samples; // does the buffer have sufficient samples?
 
619
                if (semop(buflen_sem, &bleh, 1) == -1) {
 
620
                        if (errno == EAGAIN) {
 
621
                                union semun semdat;
 
622
                                arts_debug("buffer underrun");
 
623
//                              samplesAvailable = semctl(buflen_sem,0,GETVAL,semdat);
 
624
//                              if (semctl(buflen_sem, 1, GETVAL, semdat) == 0) {
 
625
//                                      samplesAvailable = semctl(buflen_sem,0,GETVAL,semdat);
 
626
                                if ((semctl(buflen_sem, 1, GETVAL, semdat) == 0) && (semctl(buflen_sem,0,GETVAL,semdat) == 0))
 
627
                                {
 
628
                                        arts_debug("decoder requested exit");
 
629
                                        // no samples AND no room is the decoder's way of signalling completion
 
630
                                        halt();
 
631
                //              samplesAvailable = 0;
 
632
                                }
 
633
                                        samplesAvailable = 0; // 
 
634
                        } else {
 
635
                                arts_debug("something awful happened to our semaphores...");
 
636
                                // something awful has happened
 
637
                                halt();
 
638
                                samplesAvailable = 0;
 
639
                        }
 
640
                } else {
 
641
                        samplesAvailable = samples; // number of samples we pushed from buffers
 
642
                        // used to calculate the number we should zero out for an underrun
 
643
                }
 
644
                bleh.sem_flg = 0; // back to normal now
 
645
                
 
646
                if(samplesAvailable) {
 
647
                        //arts_debug("%d samples available",samplesAvailable);
 
648
                        for (int i = 0; i < samplesAvailable; 
 
649
                                        ++i, buf_pos = ((buf_pos + 1) % BACKBUFSIZ)) {
 
650
 
 
651
                                left[i] = shm_buf->left[buf_pos];
 
652
                                right[i] = shm_buf->right[buf_pos];
 
653
                        }
 
654
 
 
655
                        bleh.sem_num = 1;
 
656
                        bleh.sem_op = samplesAvailable; 
 
657
                        // 0 here CAN block, which is why this is in an if(samplesAvailable)
 
658
                        semop(buflen_sem, &bleh, 1); // mark the now-free space
 
659
                }
 
660
        }
 
661
        // zero out any samples we didn't have enough to complete - no buzz of death!
 
662
        while(static_cast<unsigned long>(samplesAvailable) < samples) {
 
663
                left[samplesAvailable] = 0.0;
 
664
                right[samplesAvailable] = 0.0;
 
665
                samplesAvailable++;
 
666
        }
 
667
}
 
668
 
 
669
void mpg123PlayObject_impl::streamEnd()
 
670
{
 
671
        arts_debug("streamEnd");
 
672
}
 
673
 
 
674
REGISTER_IMPLEMENTATION(mpg123PlayObject_impl);
 
675