~ubuntu-branches/ubuntu/karmic/mpg123/karmic

« back to all changes in this revision

Viewing changes to audio_nas.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2004-10-26 23:48:41 UTC
  • Revision ID: james.westby@ubuntu.com-20041026234841-vyigddlv7kb52nxh
Tags: upstream-0.59r
ImportĀ upstreamĀ versionĀ 0.59r

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 *  simple audio Lib .. 
 
3
 *  Network Audio System? (NAS)
 
4
 */
 
5
 
 
6
#include <sys/types.h>
 
7
#include <stdio.h>
 
8
#include <unistd.h>
 
9
#include <fcntl.h>
 
10
#include <stdlib.h>
 
11
#include <audio/audiolib.h>
 
12
#include <audio/soundlib.h>
 
13
 
 
14
#include "mpg123.h"
 
15
 
 
16
typedef struct
 
17
{
 
18
    AuServer            *aud;
 
19
    AuFlowID            flow;
 
20
    AuDeviceAttributes  *da;
 
21
    int                 numDevices;
 
22
    char                *buf;
 
23
    AuUint32            buf_size;
 
24
    AuUint32            buf_cnt;
 
25
    AuBool              data_sent;
 
26
    AuBool              finished;
 
27
} InfoRec, *InfoPtr;
 
28
 
 
29
#define NAS_SOUND_PORT_DURATION 5 /* seconds */
 
30
#define NAS_SOUND_LOW_WATER_MARK 25 /* percent */
 
31
#define NAS_MAX_FORMAT 10 /* currently, there are 7 supported formats */
 
32
 
 
33
static InfoRec info;
 
34
 
 
35
/* NAS specific routines */
 
36
 
 
37
static void
 
38
nas_sendData(AuServer *aud, InfoPtr i, AuUint32 numBytes)
 
39
{
 
40
    if (numBytes < i->buf_cnt) {
 
41
        AuWriteElement(aud, i->flow, 0, numBytes, i->buf, AuFalse, NULL);
 
42
        memmove(i->buf, i->buf + numBytes, i->buf_cnt - numBytes);
 
43
        i->buf_cnt = i->buf_cnt - numBytes;
 
44
    }
 
45
    else {
 
46
         AuWriteElement(aud, i->flow, 0, i->buf_cnt, i->buf,
 
47
                        (numBytes > i->buf_cnt), NULL);
 
48
         i->buf_cnt = 0;
 
49
    }
 
50
    i->data_sent = AuTrue;
 
51
}
 
52
 
 
53
static AuBool
 
54
nas_eventHandler(AuServer *aud, AuEvent *ev, AuEventHandlerRec *handler)
 
55
{
 
56
    InfoPtr         i = (InfoPtr) handler->data;
 
57
 
 
58
    switch (ev->type)
 
59
    {
 
60
        case AuEventTypeMonitorNotify:
 
61
            i->finished = AuTrue;
 
62
            break;
 
63
       case AuEventTypeElementNotify:
 
64
           {
 
65
               AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
 
66
 
 
67
               switch (event->kind)
 
68
               {
 
69
                   case AuElementNotifyKindLowWater:
 
70
                       nas_sendData(aud, i, event->num_bytes);
 
71
                       break;
 
72
                   case AuElementNotifyKindState:
 
73
                       switch (event->cur_state)
 
74
                       {
 
75
                           case AuStatePause:
 
76
                               if (event->reason != AuReasonUser)
 
77
                                   nas_sendData(aud, i, event->num_bytes);
 
78
                               break;
 
79
                            case AuStateStop:
 
80
                                i->finished = AuTrue;
 
81
                                break;
 
82
                       }
 
83
               }
 
84
           }
 
85
    }
 
86
    return AuTrue;
 
87
}
 
88
 
 
89
void nas_createFlow(struct audio_info_struct *ai)
 
90
{
 
91
    AuDeviceID      device = AuNone;
 
92
    AuElement       elements[2];
 
93
    unsigned char   format;
 
94
    AuUint32        buf_samples;
 
95
    int             i;
 
96
 
 
97
 
 
98
    switch(ai->format) {
 
99
    case AUDIO_FORMAT_SIGNED_16:
 
100
    default:
 
101
                if (((char) *(short *)"x")=='x') /* ugly, but painless */
 
102
                        format = AuFormatLinearSigned16LSB; /* little endian */
 
103
                else
 
104
                format = AuFormatLinearSigned16MSB; /* big endian */
 
105
        break;
 
106
    case AUDIO_FORMAT_UNSIGNED_8:
 
107
        format = AuFormatLinearUnsigned8;
 
108
        break;
 
109
    case AUDIO_FORMAT_SIGNED_8:
 
110
        format = AuFormatLinearSigned8;
 
111
        break;
 
112
    case AUDIO_FORMAT_ULAW_8:
 
113
        format = AuFormatULAW8;
 
114
        break;
 
115
    }
 
116
    /* look for an output device */
 
117
    for (i = 0; i < AuServerNumDevices(info.aud); i++)
 
118
       if (((AuDeviceKind(AuServerDevice(info.aud, i)) ==
 
119
              AuComponentKindPhysicalOutput) &&
 
120
             AuDeviceNumTracks(AuServerDevice(info.aud, i))
 
121
             ==  ai->channels )) {
 
122
            device = AuDeviceIdentifier(AuServerDevice(info.aud, i));
 
123
            break;
 
124
       }
 
125
    if (device == AuNone) {
 
126
       fprintf(stderr,
 
127
                "Couldn't find an output device providing %d channels\n",
 
128
                ai->channels);
 
129
        exit(1);
 
130
    }
 
131
 
 
132
    /* set gain */
 
133
    if(ai->gain >= 0) {
 
134
        info.da = AuGetDeviceAttributes(info.aud, device, NULL);
 
135
        if ((info.da)!=NULL) {
 
136
            AuDeviceGain(info.da) = AuFixedPointFromSum(ai->gain, 0);
 
137
            AuSetDeviceAttributes(info.aud, AuDeviceIdentifier(info.da),
 
138
                                  AuCompDeviceGainMask, info.da, NULL);
 
139
        }
 
140
        else
 
141
            fprintf(stderr,"audio/gain: setable Volume/PCM-Level not supported");
 
142
    }
 
143
    
 
144
    if (!(info.flow = AuCreateFlow(info.aud, NULL))) {
 
145
        fprintf(stderr, "Couldn't create flow\n");
 
146
        exit(1);
 
147
    }
 
148
 
 
149
    buf_samples = ai->rate * NAS_SOUND_PORT_DURATION;
 
150
 
 
151
    AuMakeElementImportClient(&elements[0],        /* element */
 
152
                              (unsigned short) ai->rate,
 
153
                                                   /* rate */
 
154
                              format,              /* format */
 
155
                              ai->channels,        /* channels */
 
156
                              AuTrue,              /* ??? */
 
157
                              buf_samples,         /* max samples */
 
158
                              (AuUint32) (buf_samples / 100
 
159
                                  * NAS_SOUND_LOW_WATER_MARK),
 
160
                                                   /* low water mark */
 
161
                              0,                   /* num actions */
 
162
                              NULL);               /* actions */
 
163
    AuMakeElementExportDevice(&elements[1],        /* element */
 
164
                              0,                   /* input */
 
165
                              device,              /* device */
 
166
                              (unsigned short) ai->rate,
 
167
                                                   /* rate */
 
168
                              AuUnlimitedSamples,  /* num samples */
 
169
                              0,                   /* num actions */
 
170
                              NULL);               /* actions */
 
171
    AuSetElements(info.aud,                        /* Au server */
 
172
                  info.flow,                       /* flow ID */
 
173
                  AuTrue,                          /* clocked */
 
174
                  2,                               /* num elements */
 
175
                  elements,                        /* elements */
 
176
                  NULL);                           /* return status */
 
177
 
 
178
    AuRegisterEventHandler(info.aud,               /* Au server */
 
179
                           AuEventHandlerIDMask,   /* value mask */
 
180
                           0,                      /* type */
 
181
                           info.flow,              /* id */
 
182
                           nas_eventHandler,       /* callback */
 
183
                           (AuPointer) &info);     /* data */
 
184
 
 
185
    info.buf_size = buf_samples * ai->channels * AuSizeofFormat(format);
 
186
    info.buf = (char *) malloc(info.buf_size);
 
187
    if (info.buf == NULL) {
 
188
        fprintf(stderr, "Unable to allocate input/output buffer of size %ld\n",
 
189
             info.buf_size);
 
190
        exit(1);
 
191
    }
 
192
    info.buf_cnt = 0;
 
193
    info.data_sent = AuFalse;
 
194
    info.finished = AuFalse;
 
195
    
 
196
    AuStartFlow(info.aud,                          /* Au server */
 
197
                info.flow,                         /* id */
 
198
                NULL);                             /* status */
 
199
}
 
200
 
 
201
 
 
202
void nas_flush()
 
203
{
 
204
    AuEvent         ev;
 
205
    
 
206
    while ((!info.data_sent) && (!info.finished)) {
 
207
        AuNextEvent(info.aud, AuTrue, &ev);
 
208
        AuDispatchEvent(info.aud, &ev);
 
209
    }
 
210
    info.data_sent = AuFalse;
 
211
}
 
212
 
 
213
/* required functions */
 
214
 
 
215
int audio_open(struct audio_info_struct *ai)
 
216
{
 
217
    if(!ai)
 
218
        return -1;
 
219
 
 
220
    if (!(info.aud = AuOpenServer(ai->device, 0, NULL, 0, NULL, NULL))) {
 
221
        if (ai->device==NULL)
 
222
            fprintf(stderr,"could not open default NAS server\n");
 
223
        else
 
224
            fprintf(stderr,"could not open NAS server %s\n",
 
225
                    ai->device);
 
226
        exit(1);
 
227
    }
 
228
    info.buf_size = 0;
 
229
        
 
230
    return 0;
 
231
}
 
232
    
 
233
int audio_reset_parameters(struct audio_info_struct *ai)
 
234
{
 
235
    int ret;
 
236
 
 
237
    ret = audio_close(ai);
 
238
    if (ret >= 0)
 
239
        ret = audio_open(ai);
 
240
    return ret;
 
241
}
 
242
 
 
243
extern int audio_rate_best_match(struct audio_info_struct *ai)
 
244
{
 
245
    int maxRate, minRate;
 
246
 
 
247
    if(!ai || ai->rate < 0)
 
248
        return -1;
 
249
    maxRate =  AuServerMaxSampleRate(info.aud);
 
250
    minRate =  AuServerMinSampleRate(info.aud);
 
251
    if (ai->rate > maxRate) ai->rate = maxRate;
 
252
    if (ai->rate < minRate) ai->rate = minRate;
 
253
    return 0;
 
254
}
 
255
 
 
256
int audio_set_rate(struct audio_info_struct *ai)
 
257
{
 
258
    return 0;
 
259
}
 
260
 
 
261
int audio_set_channels(struct audio_info_struct *ai)
 
262
{
 
263
    return 0;
 
264
}
 
265
 
 
266
int audio_set_format(struct audio_info_struct *ai)
 
267
{
 
268
    return 0;
 
269
}
 
270
 
 
271
int audio_get_formats(struct audio_info_struct *ai)
 
272
{
 
273
    int i, j, k, ret;
 
274
 
 
275
    ret=0;
 
276
    j = AuServerNumFormats(info.aud);
 
277
    for (i=0; i<j; i++) {
 
278
        k=AuServerFormat(info.aud,i);
 
279
        switch (k)
 
280
        {
 
281
        case AuFormatULAW8:
 
282
            ret |= AUDIO_FORMAT_ULAW_8;
 
283
            break;
 
284
        case AuFormatLinearUnsigned8:
 
285
            ret |= AUDIO_FORMAT_UNSIGNED_8;
 
286
            break;
 
287
        case AuFormatLinearSigned8:
 
288
            ret |= AUDIO_FORMAT_SIGNED_8;
 
289
            break;
 
290
        case AuFormatLinearSigned16LSB:
 
291
            ret |= AUDIO_FORMAT_SIGNED_16;
 
292
            break;
 
293
        }
 
294
    }
 
295
    return ret;
 
296
}
 
297
 
 
298
int audio_play_samples(struct audio_info_struct *ai,unsigned char *buf,int len)
 
299
{
 
300
    int buf_cnt = 0;
 
301
 
 
302
    if (info.buf_size == 0) nas_createFlow(ai);
 
303
    
 
304
    while ((info.buf_cnt + (len - buf_cnt)) >  info.buf_size) {
 
305
        memcpy(info.buf + info.buf_cnt,
 
306
               buf + buf_cnt,
 
307
               (info.buf_size - info.buf_cnt));
 
308
        buf_cnt += (info.buf_size - info.buf_cnt);
 
309
        info.buf_cnt += (info.buf_size - info.buf_cnt);
 
310
        nas_flush();
 
311
    }
 
312
    memcpy(info.buf + info.buf_cnt,
 
313
           buf + buf_cnt,
 
314
           (len - buf_cnt));
 
315
    info.buf_cnt += (len - buf_cnt);
 
316
    
 
317
    return len;
 
318
}
 
319
 
 
320
int audio_close(struct audio_info_struct *ai)
 
321
{
 
322
    if (info.aud == NULL) {
 
323
        return 0;
 
324
    }
 
325
    
 
326
    if (info.buf_size == 0) {
 
327
        /* Au server opened, but not yet initialized */
 
328
        AuCloseServer(info.aud);
 
329
        return 0;
 
330
    }
 
331
        
 
332
    while (!info.finished) {
 
333
        nas_flush();
 
334
    }
 
335
    AuCloseServer(info.aud);
 
336
    free(info.buf);
 
337
    
 
338
    return 0;
 
339
}