~ubuntu-dev/mplayer/ubuntu-feisty

« back to all changes in this revision

Viewing changes to libao2/ao_sgi.c

  • Committer: Reinhard Tartler
  • Date: 2006-07-08 08:45:33 UTC
  • Revision ID: siretart@tauware.de-20060708084533-dbc155bde7122e78
imported mplayer_0.99+1.0pre7try2+cvs20060117

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  ao_sgi - sgi/irix output plugin for MPlayer
 
3
 
 
4
  22oct2001 oliver.schoenbrunner@jku.at
 
5
  
 
6
*/
 
7
 
 
8
#include <stdio.h>
 
9
#include <stdlib.h>
 
10
#include <unistd.h>
 
11
#include <errno.h>
 
12
#include <dmedia/audio.h>
 
13
 
 
14
#include "audio_out.h"
 
15
#include "audio_out_internal.h"
 
16
#include "mp_msg.h"
 
17
#include "help_mp.h"
 
18
#include "libaf/af_format.h"
 
19
 
 
20
static ao_info_t info = 
 
21
{
 
22
        "sgi audio output",
 
23
        "sgi",
 
24
        "Oliver Schoenbrunner",
 
25
        ""
 
26
};
 
27
 
 
28
LIBAO_EXTERN(sgi)
 
29
 
 
30
 
 
31
static ALconfig ao_config;
 
32
static ALport   ao_port;
 
33
static int sample_rate;
 
34
static int queue_size;
 
35
static int bytes_per_frame;
 
36
 
 
37
/**
 
38
 * \param   [in/out]  format
 
39
 * \param   [out]     width
 
40
 *
 
41
 * \return  the closest matching SGI AL sample format
 
42
 *
 
43
 * \note    width is set to required per-channel sample width
 
44
 *          format is updated to match the SGI AL sample format
 
45
 */
 
46
static int fmt2sgial(int *format, int *width) {
 
47
  int smpfmt = AL_SAMPFMT_TWOSCOMP;
 
48
 
 
49
  /* SGI AL only supports float and signed integers in native
 
50
   * endianess. If this is something else, we must rely on the audio
 
51
   * filter to convert it to a compatible format. */
 
52
 
 
53
  /* 24-bit audio is supported, but only with 32-bit alignment.
 
54
   * mplayer's 24-bit format is packed, unfortunately.
 
55
   * So we must upgrade 24-bit requests to 32 bits. Then we drop the
 
56
   * lowest 8 bits during playback. */
 
57
 
 
58
  switch(*format) {
 
59
  case AF_FORMAT_U8:
 
60
  case AF_FORMAT_S8:
 
61
    *width = AL_SAMPLE_8;
 
62
    *format = AF_FORMAT_S8;
 
63
    break;
 
64
 
 
65
  case AF_FORMAT_U16_LE:
 
66
  case AF_FORMAT_U16_BE:
 
67
  case AF_FORMAT_S16_LE:
 
68
  case AF_FORMAT_S16_BE:
 
69
    *width = AL_SAMPLE_16;
 
70
    *format = AF_FORMAT_S16_NE;
 
71
    break;
 
72
 
 
73
  case AF_FORMAT_U24_LE:
 
74
  case AF_FORMAT_U24_BE:
 
75
  case AF_FORMAT_S24_LE:
 
76
  case AF_FORMAT_S24_BE:
 
77
  case AF_FORMAT_U32_LE:
 
78
  case AF_FORMAT_U32_BE:
 
79
  case AF_FORMAT_S32_LE:
 
80
  case AF_FORMAT_S32_BE:
 
81
    *width = AL_SAMPLE_24;
 
82
    *format = AF_FORMAT_S32_NE;
 
83
    break;
 
84
 
 
85
  case AF_FORMAT_FLOAT_LE:
 
86
  case AF_FORMAT_FLOAT_BE:
 
87
    *width = 4;
 
88
    *format = AF_FORMAT_FLOAT_NE;
 
89
    smpfmt = AL_SAMPFMT_FLOAT;
 
90
    break;
 
91
 
 
92
  default:
 
93
    *width = AL_SAMPLE_16;
 
94
    *format = AF_FORMAT_S16_NE;
 
95
    break;
 
96
 
 
97
  }
 
98
 
 
99
  return smpfmt;
 
100
}
 
101
 
 
102
// to set/get/query special features/parameters
 
103
static int control(int cmd, void *arg){
 
104
  
 
105
  mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_INFO);
 
106
  
 
107
  switch(cmd) {
 
108
  case AOCONTROL_QUERY_FORMAT:
 
109
    /* Do not reject any format: return the closest matching
 
110
     * format if the request is not supported natively. */
 
111
    return CONTROL_TRUE;
 
112
  }
 
113
 
 
114
  return CONTROL_UNKNOWN;
 
115
}
 
116
 
 
117
// open & setup audio device
 
118
// return: 1=success 0=fail
 
119
static int init(int rate, int channels, int format, int flags) {
 
120
 
 
121
  int smpwidth, smpfmt;
 
122
  int rv = AL_DEFAULT_OUTPUT;
 
123
 
 
124
  smpfmt = fmt2sgial(&format, &smpwidth);
 
125
 
 
126
  mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_InitInfo, rate, (channels > 1) ? "Stereo" : "Mono", af_fmt2str_short(format));
 
127
  
 
128
  { /* from /usr/share/src/dmedia/audio/setrate.c */
 
129
  
 
130
    double frate, realrate;
 
131
    ALpv x[2];
 
132
 
 
133
    if(ao_subdevice) {
 
134
      rv = alGetResourceByName(AL_SYSTEM, ao_subdevice, AL_OUTPUT_DEVICE_TYPE);
 
135
      if (!rv) {
 
136
        mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InvalidDevice);
 
137
        return 0;
 
138
      }
 
139
    }
 
140
    
 
141
    frate = rate;
 
142
   
 
143
    x[0].param = AL_RATE;
 
144
    x[0].value.ll = alDoubleToFixed(rate);
 
145
    x[1].param = AL_MASTER_CLOCK;
 
146
    x[1].value.i = AL_CRYSTAL_MCLK_TYPE;
 
147
 
 
148
    if (alSetParams(rv,x, 2)<0) {
 
149
      mp_msg(MSGT_AO, MSGL_WARN, MSGTR_AO_SGI_CantSetParms_Samplerate, alGetErrorString(oserror()));
 
150
    }
 
151
    
 
152
    if (x[0].sizeOut < 0) {
 
153
      mp_msg(MSGT_AO, MSGL_WARN, MSGTR_AO_SGI_CantSetAlRate);
 
154
    }
 
155
 
 
156
    if (alGetParams(rv,x, 1)<0) {
 
157
      mp_msg(MSGT_AO, MSGL_WARN, MSGTR_AO_SGI_CantGetParms, alGetErrorString(oserror()));
 
158
    }
 
159
    
 
160
    realrate = alFixedToDouble(x[0].value.ll);
 
161
    if (frate != realrate) {
 
162
      mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_SampleRateInfo, realrate, frate);
 
163
    } 
 
164
    sample_rate = (int)realrate;
 
165
  }
 
166
  
 
167
  bytes_per_frame = channels * smpwidth;
 
168
 
 
169
  ao_data.samplerate = sample_rate;
 
170
  ao_data.channels = channels;
 
171
  ao_data.format = format;
 
172
  ao_data.bps = sample_rate * bytes_per_frame;
 
173
  ao_data.buffersize=131072;
 
174
  ao_data.outburst = ao_data.buffersize/16;
 
175
  
 
176
  ao_config = alNewConfig();
 
177
  
 
178
  if (!ao_config) {
 
179
    mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InitConfigError, alGetErrorString(oserror()));
 
180
    return 0;
 
181
  }
 
182
  
 
183
  if(alSetChannels(ao_config, channels) < 0 ||
 
184
     alSetWidth(ao_config, smpwidth) < 0 ||
 
185
     alSetSampFmt(ao_config, smpfmt) < 0 ||
 
186
     alSetQueueSize(ao_config, sample_rate) < 0 ||
 
187
     alSetDevice(ao_config, rv) < 0) {
 
188
    mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InitConfigError, alGetErrorString(oserror()));
 
189
    return 0;
 
190
  }
 
191
  
 
192
  ao_port = alOpenPort("mplayer", "w", ao_config);
 
193
  
 
194
  if (!ao_port) {
 
195
    mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_SGI_InitOpenAudioFailed, alGetErrorString(oserror()));
 
196
    return 0;
 
197
  }
 
198
  
 
199
  // printf("ao_sgi, init: port %d config %d\n", ao_port, ao_config);
 
200
  queue_size = alGetQueueSize(ao_config);
 
201
  return 1;  
 
202
 
 
203
}
 
204
 
 
205
// close audio device
 
206
static void uninit(int immed) {
 
207
 
 
208
  /* TODO: samplerate should be set back to the value before mplayer was started! */
 
209
 
 
210
  mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_Uninit);
 
211
 
 
212
  if (ao_config) {
 
213
    alFreeConfig(ao_config);
 
214
    ao_config = NULL;
 
215
  }
 
216
 
 
217
  if (ao_port) {
 
218
    if (!immed)
 
219
    while(alGetFilled(ao_port) > 0) sginap(1);  
 
220
    alClosePort(ao_port);
 
221
    ao_port = NULL;
 
222
  }
 
223
        
 
224
}
 
225
 
 
226
// stop playing and empty buffers (for seeking/pause)
 
227
static void reset() {
 
228
  
 
229
  mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_Reset);
 
230
  
 
231
  alDiscardFrames(ao_port, queue_size);
 
232
}
 
233
 
 
234
// stop playing, keep buffers (for pause)
 
235
static void audio_pause() {
 
236
    
 
237
  mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_PauseInfo);
 
238
    
 
239
}
 
240
 
 
241
// resume playing, after audio_pause()
 
242
static void audio_resume() {
 
243
 
 
244
  mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_SGI_ResumeInfo);
 
245
 
 
246
}
 
247
 
 
248
// return: how many bytes can be played without blocking
 
249
static int get_space() {
 
250
  
 
251
  // printf("ao_sgi, get_space: (ao_outburst %d)\n", ao_data.outburst);
 
252
  // printf("ao_sgi, get_space: alGetFillable [%d] \n", alGetFillable(ao_port));
 
253
  
 
254
  return alGetFillable(ao_port) * bytes_per_frame;
 
255
    
 
256
}
 
257
 
 
258
 
 
259
// plays 'len' bytes of 'data'
 
260
// it should round it down to outburst*n
 
261
// return: number of bytes played
 
262
static int play(void* data, int len, int flags) {
 
263
    
 
264
  /* Always process data in quadword-aligned chunks (64-bits). */
 
265
  const int plen = len / (sizeof(uint64_t) * bytes_per_frame);
 
266
  const int framecount = plen * sizeof(uint64_t);
 
267
 
 
268
  // printf("ao_sgi, play: len %d flags %d (%d %d)\n", len, flags, ao_port, ao_config);
 
269
  // printf("channels %d\n", ao_data.channels);
 
270
 
 
271
  if(ao_data.format == AF_FORMAT_S32_NE) {
 
272
    /* The zen of this is explained in fmt2sgial() */
 
273
    int32_t *smpls = data;
 
274
    const int32_t *smple = smpls + (framecount * ao_data.channels);
 
275
    while(smpls < smple)
 
276
      *smpls++ >>= 8;
 
277
  }
 
278
 
 
279
  alWriteFrames(ao_port, data, framecount);
 
280
 
 
281
  return framecount * bytes_per_frame;
 
282
  
 
283
}
 
284
 
 
285
// return: delay in seconds between first and last sample in buffer
 
286
static float get_delay(){
 
287
  
 
288
  // printf("ao_sgi, get_delay: (ao_buffersize %d)\n", ao_buffersize);
 
289
  
 
290
  // return  (float)queue_size/((float)sample_rate);
 
291
  const int outstanding = alGetFilled(ao_port);
 
292
  return (float)((outstanding < 0) ? queue_size : outstanding) /
 
293
    ((float)sample_rate);
 
294
}
 
295
 
 
296
 
 
297
 
 
298
 
 
299
 
 
300