~ubuntu-branches/ubuntu/precise/dbmix/precise

« back to all changes in this revision

Viewing changes to dbaudiolib/DBAudio_Init.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2003-06-09 21:54:06 UTC
  • Revision ID: james.westby@ubuntu.com-20030609215406-8c0wou3z9jdk3gwp
Tags: upstream-0.9.8
ImportĀ upstreamĀ versionĀ 0.9.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
  Author:  Bob Dean
 
4
  Copyright (c) 1999, 2000
 
5
 
 
6
 
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public Licensse as published by
 
9
   the Free Software Foundation; either version 2 of the License, or
 
10
   (at your option) any later version.
 
11
 
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
 
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program; if not, write to the Free Software
 
19
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
20
 
 
21
 */
 
22
 
 
23
#ifdef __cplusplus
 
24
extern "C"
 
25
{
 
26
#endif
 
27
 
 
28
#include <stdio.h>
 
29
#include <unistd.h>
 
30
#include <stdlib.h>
 
31
#include <errno.h>
 
32
#include <string.h>
 
33
#include <sys/types.h>
 
34
#include <limits.h>
 
35
#include <fcntl.h>
 
36
#include <signal.h>
 
37
#include <stdarg.h>
 
38
#include <sys/shm.h>
 
39
#include <sys/ipc.h>
 
40
#include <sys/msg.h>
 
41
#include <glib.h>
 
42
#include <math.h>
 
43
 
 
44
#include <dbsoundcard.h>
 
45
 
 
46
#include <dbchannel.h>
 
47
#include <dbdebug.h>
 
48
#include <dbaudiolib.h>
 
49
 
 
50
#include "prototypes.h"
 
51
 
 
52
        /* variables to access DBMix channels shared memory */
 
53
        int shmid, sysshmid;
 
54
        dbfsd_data * sysdata = NULL;
 
55
        local_channel * local_channels = NULL;
 
56
        /* static local_channel * cue_channels; */
 
57
        local_channel * ch = NULL;
 
58
 
 
59
        /* variables to describe the input audio stream */
 
60
        int format;
 
61
        int sample_rate;
 
62
        int num_channels;
 
63
        int paused;
 
64
 
 
65
        /* globally static audio write variables */
 
66
        float local_pitch;
 
67
        float sample1, sample2;
 
68
        float float_index;
 
69
        int   sampleindex;
 
70
        int   outlen;
 
71
 
 
72
        signed short output_buf[OUTPUT_BUFSIZE];  /* buffer used to hold main output to dbfsd */
 
73
        signed short cue_buf[OUTPUT_BUFSIZE];     /* buffer used to hold cue output to dbfsd */
 
74
        signed short conv_buf[OUTPUT_BUFSIZE];    /* buffer used to hold format converted input */
 
75
 
 
76
        extern int errno;
 
77
        extern int debug_level; /* declared in debug module */
 
78
 
 
79
        /*
 
80
          DBAudio_Init - initializes this instance.  If an error occurs, returns FAILURE
 
81
          otherwise, returns SUCCESS.
 
82
 
 
83
          Parameters: 
 
84
          fmt   - format of input data (see OSS Programmer's Manual 
 
85
          http://www.opensound.com/pguide/index.html)
 
86
          rte   - input data rate expressed as a whole integer. i.e. 44.1 kHz = 44100
 
87
          numch - number of channels in the input data
 
88
          type  - DBMix channel type, see enum channel_type_e in channel.h
 
89
          chindex - if 0 returns the first available channel, otherwise tries to use the
 
90
          channel associated with (chindex -1). If this channel is not free,
 
91
          FAILURE is returned.
 
92
 
 
93
          Pre Condition:
 
94
          - None
 
95
 
 
96
          Post Condition
 
97
          - Shared memory channel data created by dbfsd is attached to this process..
 
98
          - From this data, determine the next free/unused channel.  The pointer
 
99
          to this channel is stored in the static global ch variable.
 
100
          - Open communication and signal pipes for communicating with dbfsd
 
101
 
 
102
          Note: this function makes use of goto statements.  More specifically,
 
103
            a label called cleanup exists at the end of the function allowing
 
104
            a single cleanup point in the function.  This is a result of the 
 
105
                        coding standards my group at work enforces. Despite what you were
 
106
                        taught about the evils of goto, this method of their use makes the
 
107
                        code cleaner and more elegant, otherwise the exact same shmdt() 
 
108
                        statements would be scattered half a dozen times through out the code.
 
109
                        The single "goto cleanup" line replaces 4-10 lines of repetitive
 
110
                        cleanup code each time it is used.
 
111
        */
 
112
        int DBAudio_Init(char * name, int fmt, int rte, int numch,
 
113
                                         enum channel_type_e type, int chindex)
 
114
        {
 
115
                char init_buffer[PIPE_BUF];
 
116
                int templen;
 
117
 
 
118
#ifdef DBMIX_DEBUG
 
119
                debug_level = 1;
 
120
#else
 
121
                debug_level = 0;
 
122
#endif
 
123
 
 
124
                /* init errno to SUCCESS to maintain error state */
 
125
                errno = SUCCESS;
 
126
                
 
127
                if (ch != NULL)
 
128
                {
 
129
                        goto cleanup;
 
130
                }
 
131
 
 
132
                if (local_channels != NULL)
 
133
                {
 
134
                        goto cleanup;
 
135
                }
 
136
                
 
137
                if (sysdata != NULL)
 
138
                {
 
139
                        goto cleanup;
 
140
                }
 
141
 
 
142
                /* init variables used by DBAudio_Write() */
 
143
                local_pitch = 1.0;
 
144
                sample1 = sample2 = 0.0;
 
145
                float_index = 0.0;
 
146
                sampleindex = 0;
 
147
                outlen = 0;
 
148
                
 
149
                /* verify format */
 
150
                if (fmt != 0)
 
151
                {
 
152
                        format = fmt;
 
153
                }
 
154
                else
 
155
                {
 
156
                        format = AFMT_S16_NE;
 
157
                }
 
158
 
 
159
                /* verify sample rate */
 
160
                if (rte == 0)
 
161
                {
 
162
                        sample_rate = DB_SAMPLE_RATE;
 
163
                } 
 
164
                else 
 
165
                {
 
166
                        if ((rte >= 8000) && (rte < 49000))
 
167
                        {
 
168
                                sample_rate = rte;
 
169
                        }
 
170
                        else
 
171
                        {
 
172
                                errno = ERROR_BAD_SAMPLERATE;
 
173
                                goto cleanup;
 
174
                        }
 
175
                }
 
176
 
 
177
                /* verify number of channels */
 
178
                switch(numch)
 
179
                {
 
180
                        case 0: 
 
181
                                num_channels = 2; 
 
182
                                break;  /* default to stereo */
 
183
 
 
184
                        case 1: 
 
185
                                num_channels = 1; 
 
186
                                break;  /* mono */
 
187
 
 
188
                        case 2: 
 
189
                                num_channels = 2; 
 
190
                                break;  /* stereo */
 
191
 
 
192
                        default: 
 
193
                                errno = ERROR_BAD_NUMCH; 
 
194
                                goto cleanup;
 
195
                }
 
196
 
 
197
 
 
198
                /* Get system data */
 
199
                {
 
200
                        sysshmid = shmget((key_t) DB_SYSTEM_SM_KEY, sizeof(dbfsd_data), 
 
201
                                                          0666 | O_RDWR );
 
202
                
 
203
                        if (sysshmid == -1) 
 
204
                        {
 
205
                                Error("DBAudioLib ERROR: could not create shared memory for system data.\n Is dbfsd running?");
 
206
                                errno = ERROR_INIT_FAILURE;
 
207
                                goto cleanup; 
 
208
                        }
 
209
                
 
210
                        sysdata = shmat(sysshmid,(void *)0, 0);
 
211
                
 
212
                        if ((int)sysdata == -1)
 
213
                        {
 
214
                                Error("DBAudioLib ERROR: error attaching system data shared memory.");  
 
215
                                errno = ERROR_INIT_FAILURE;
 
216
                                goto cleanup;
 
217
                        }
 
218
                
 
219
                        /* verify that there is a free channel into dbfsd */
 
220
                        if (sysdata->free_channel_index == -1)
 
221
                        {
 
222
                                ch = NULL;
 
223
                                
 
224
                                Error("DBAudio_Init: no free channels.");
 
225
 
 
226
                                if (shmdt(sysdata) == -1)
 
227
                                {
 
228
                                        Error("DBAudio_Init: could not detach system data memory segment.");
 
229
                                        errno = ERROR_INIT_FAILURE;
 
230
                                        goto cleanup;
 
231
                                }
 
232
                        
 
233
                                errno = ERROR_NO_FREE_CHANNELS;
 
234
                                goto cleanup;
 
235
                        }
 
236
                }
 
237
                /* End get system data */
 
238
 
 
239
                /* retrieve the channel memory id */
 
240
                {
 
241
                        shmid = shmget((key_t) DB_CHANNELS_SM_KEY, 
 
242
                                                   (sysdata->num_channels * sizeof(local_channel)), 0666);
 
243
                
 
244
                        if (shmid == -1) 
 
245
                        {
 
246
                                Error("DBAudioLib ERROR: error creating channel shared memory.");
 
247
                                errno = ERROR_INIT_FAILURE;
 
248
                                goto cleanup;
 
249
                        }
 
250
                        else
 
251
                        {
 
252
                                Debug("DBAudioLib: shmid is: %d ",shmid);
 
253
                        }
 
254
                
 
255
                        /* attach the channel memory segment*/
 
256
                        local_channels = (local_channel *) shmat(shmid,(void *)0, 0);
 
257
                
 
258
                        if ((int)local_channels == -1)
 
259
                        {
 
260
                                Error("DBAudioLib ERROR: error attaching channel shared memory.");
 
261
 
 
262
                                errno = ERROR_INIT_FAILURE;
 
263
                                goto cleanup;
 
264
                        }
 
265
 
 
266
                        /*  get channel id */           
 
267
                        if (chindex == 0)
 
268
                        {
 
269
                                ch = &(local_channels[sysdata->free_channel_index]);
 
270
                        }
 
271
                        else
 
272
                        {
 
273
                                /* chindex is begins at 1, so decrement to directly reference the 
 
274
                   channel array */
 
275
                                chindex--;
 
276
 
 
277
                                if ((chindex < 0) || (chindex > sysdata->num_channels))
 
278
                                {
 
279
                                        errno = ERROR_BAD_CHANNEL_ID;
 
280
                                        goto cleanup;
 
281
                                }
 
282
                        
 
283
                                if (local_channels[chindex].free_channel)
 
284
                                {
 
285
                                        ch = &(local_channels[chindex]);
 
286
                                }
 
287
                        }
 
288
 
 
289
                        Debug("DBAudioLib: opening comm pipe:  %s",ch->comm_filename);
 
290
                
 
291
                        /* open comm pipe to server */
 
292
                        if ((ch->client_comm_fd = open(ch->comm_filename, O_WRONLY)) == -1)
 
293
                        {
 
294
                                Debug("%s",ch->comm_filename);
 
295
 
 
296
                                DBAudio_perror("DBAudioLib: Error opening comm pipe.");
 
297
                                errno = ERROR_INIT_FAILURE;
 
298
                                goto cleanup;
 
299
                        }
 
300
 
 
301
                        Debug("comm fd is: %d\n",ch->client_comm_fd);
 
302
 
 
303
                        if (CUE_ENABLED)
 
304
                        {
 
305
                                printf("flags is %d\n",ch->channel_flags);
 
306
 
 
307
                                /* open cue_pipe to be NON BLOCKING -- very important since the server does
 
308
                                   not check the cue channel with its select() call*/
 
309
                                Debug("DBAudioLib: opening cue pipe: %s",ch->cue_filename);
 
310
 
 
311
                                if ((ch->client_cue_fd = open(ch->cue_filename, O_WRONLY | O_NONBLOCK)) == -1)
 
312
                                {
 
313
                                        Debug("%s",ch->cue_filename);
 
314
                                        DBAudio_perror("DBAudioLib: Error opening cue pipe.");
 
315
                                        errno = ERROR_INIT_FAILURE;
 
316
                                        goto cleanup;
 
317
                                }
 
318
 
 
319
                                Debug("Cue fd is: %d\n",ch->client_cue_fd);
 
320
                        }
 
321
                
 
322
                        ch->left_gain = DEFAULT_GAIN;
 
323
                        ch->right_gain = DEFAULT_GAIN;
 
324
                        ch->cue = FALSE;
 
325
                        ch->channel_type = type;
 
326
                        ch->base_pitch = DEFAULT_PITCH;
 
327
                
 
328
                        switch(ch->channel_type)
 
329
                        {
 
330
                                case PIPE_CHANNEL:
 
331
                                        Debug("DBAudioLib: Channel type: PIPE CHANNEL");
 
332
                                        break;
 
333
                                default:
 
334
                                        break;
 
335
                        }
 
336
 
 
337
                        /* update channel name  check against 48 to allow for channel index */
 
338
                        DBAudio_Set_Channel_Name(name);
 
339
                } /* end retrieve the channel memory id */
 
340
 
 
341
                DBAudio_Set_Rate(rte);
 
342
 
 
343
                /* clear msg queue */
 
344
                if (ch->msg_q_id != -1)
 
345
                {
 
346
                        dbfsd_msg msg;
 
347
 
 
348
                        while (msgrcv(ch->msg_q_id, &msg,sizeof(dbfsd_msg) - sizeof(long int),0,IPC_NOWAIT) != -1)
 
349
                        {
 
350
                                Debug("DBAudio_Init: cleared message %d",msg.msg_type);
 
351
                        }
 
352
                }
 
353
 
 
354
                /* init message handler to NULL */
 
355
                ch->message_handler = NULL;
 
356
 
 
357
                /* init sample buffer */
 
358
                {
 
359
                        ch->sampler_state = SAMPLER_OFF;
 
360
                        ch->sampler_bufsize = (ch->sampler_time   /* number of seconds */
 
361
                                                                  * (DB_SAMPLE_SIZE * DB_CHANNEL_NUM_CHANNELS) /* size of 1 stereo sample */
 
362
                                                                  * DB_SAMPLE_RATE); /* num samples per second */
 
363
                        ch->sampler_size = 0;
 
364
                        ch->sampler_readoffset = 0;
 
365
                        ch->sampler_startoffset = 0;
 
366
                        ch->sampler_buf = (char *) malloc(ch->sampler_bufsize);
 
367
 
 
368
                        Debug("sampler bufsize is: %d",ch->sampler_bufsize);
 
369
                }
 
370
                
 
371
                /* write an empty buffer to the mixer to init this channel */
 
372
                {
 
373
                        memset(init_buffer,0,PIPE_BUF);
 
374
                        ch->cue = TRUE;
 
375
                        Debug("writing init buffer... \n");
 
376
                        templen = PIPE_BUF;
 
377
                        
 
378
                        if (DBAudio_Write(init_buffer,templen) == FAILURE)
 
379
                        {
 
380
                                DBAudio_perror("Error writing init data to channel:: ");
 
381
                        }
 
382
                        
 
383
                        Debug("done\n");
 
384
                        ch->cue = FALSE;
 
385
                        
 
386
                        Debug("DBAudioLib: dbaudio_init complete.");
 
387
                }
 
388
 
 
389
        cleanup:
 
390
 
 
391
                /* ENOMSG is a side effect of opening/clearing the message queue, so remap it */
 
392
                if (errno == ENOMSG) errno = SUCCESS;
 
393
 
 
394
                /* if error, retur to initial state */
 
395
                if (errno != SUCCESS)
 
396
                {
 
397
                        ch = NULL;
 
398
 
 
399
                        if (local_channels != NULL)
 
400
                        {
 
401
                                shmdt(local_channels);
 
402
                        }
 
403
 
 
404
                        if (sysdata != NULL)
 
405
                        {
 
406
                                shmdt(sysdata);
 
407
                        }
 
408
 
 
409
                        return FAILURE;
 
410
                }
 
411
 
 
412
                return SUCCESS;
 
413
        }
 
414
 
 
415
 
 
416
#ifdef __cplusplus
 
417
}
 
418
#endif
 
419
 
 
420