~ubuntu-dev/mplayer/ubuntu-feisty

« back to all changes in this revision

Viewing changes to libao2/ao_openal.c

  • Committer: Reinhard Tartler
  • Date: 2006-07-08 08:47:54 UTC
  • Revision ID: siretart@tauware.de-20060708084754-c3ff228cc9c2d8de
upgrade to pre8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * ao_openal.c - OpenAL audio output driver for MPlayer
 
3
 *
 
4
 * This driver is under the same license as MPlayer.
 
5
 * (http://www.mplayerhq.hu)
 
6
 *
 
7
 * Copyleft 2006 by Reimar D�ffinger (Reimar.Doeffinger@stud.uni-karlsruhe.de)
 
8
 */
 
9
 
 
10
#include <stdlib.h>
 
11
#include <stdio.h>
 
12
#include <inttypes.h>
 
13
#include <AL/alc.h>
 
14
#include <AL/al.h>
 
15
 
 
16
#include "config.h"
 
17
#include "mp_msg.h"
 
18
#include "help_mp.h"
 
19
 
 
20
#include "audio_out.h"
 
21
#include "audio_out_internal.h"
 
22
#include "libaf/af_format.h"
 
23
#include "osdep/timer.h"
 
24
#include "subopt-helper.h"
 
25
 
 
26
static ao_info_t info = 
 
27
{
 
28
  "OpenAL audio output",
 
29
  "openal",
 
30
  "Reimar D�ffinger <Reimar.Doeffinger@stud.uni-karlsruhe.de>",
 
31
  ""
 
32
};
 
33
 
 
34
LIBAO_EXTERN(openal)
 
35
 
 
36
#define MAX_CHANS 6
 
37
#define NUM_BUF 128
 
38
#define CHUNK_SIZE 512
 
39
static ALuint buffers[MAX_CHANS][NUM_BUF];
 
40
static ALuint sources[MAX_CHANS];
 
41
 
 
42
static int cur_buf[MAX_CHANS];
 
43
static int unqueue_buf[MAX_CHANS];
 
44
static int16_t *tmpbuf;
 
45
 
 
46
 
 
47
static int control(int cmd, void *arg) {
 
48
  return CONTROL_UNKNOWN;
 
49
}
 
50
 
 
51
/**
 
52
 * \brief print suboption usage help
 
53
 */
 
54
static void print_help(void) {
 
55
  mp_msg(MSGT_AO, MSGL_FATAL,
 
56
          "\n-ao openal commandline help:\n"
 
57
          "Example: mplayer -ao openal\n"
 
58
          "\nOptions:\n"
 
59
        );
 
60
}
 
61
 
 
62
static int init(int rate, int channels, int format, int flags) {
 
63
  ALCdevice *dev = NULL;
 
64
  ALCcontext *ctx = NULL;
 
65
  ALint bufrate;
 
66
  int i;
 
67
  opt_t subopts[] = {
 
68
    {NULL}
 
69
  };
 
70
  if (subopt_parse(ao_subdevice, subopts) != 0) {
 
71
    print_help();
 
72
    return 0;
 
73
  }
 
74
  if (channels > MAX_CHANS) {
 
75
    mp_msg(MSGT_AO, MSGL_FATAL, "[OpenAL] Invalid number of channels: %i\n", channels);
 
76
    goto err_out;
 
77
  }
 
78
  dev = alcOpenDevice(NULL);
 
79
  if (!dev) {
 
80
    mp_msg(MSGT_AO, MSGL_FATAL, "[OpenAL] could not open device\n");
 
81
    goto err_out;
 
82
  }
 
83
  ctx = alcCreateContext(dev, NULL);
 
84
  alcMakeContextCurrent(ctx);
 
85
  for (i = 0; i < channels; i++) {
 
86
    cur_buf[i] = 0;
 
87
    unqueue_buf[i] = 0;
 
88
    alGenBuffers(NUM_BUF, buffers[i]);
 
89
  }
 
90
  alGenSources(channels, sources);
 
91
  alSource3f(sources[0], AL_POSITION, 0, 0, 10);
 
92
  ao_data.channels = channels;
 
93
  alGetBufferi(buffers[0][0], AL_FREQUENCY, &bufrate);
 
94
  ao_data.samplerate = rate = bufrate;
 
95
  ao_data.format = AF_FORMAT_S16_NE;
 
96
  ao_data.bps = channels * rate * 2;
 
97
  ao_data.buffersize = CHUNK_SIZE * NUM_BUF;
 
98
  ao_data.outburst = channels * CHUNK_SIZE;
 
99
  tmpbuf = (int16_t *)malloc(CHUNK_SIZE);
 
100
  return 1;
 
101
 
 
102
err_out:
 
103
  return 0;
 
104
}
 
105
 
 
106
// close audio device
 
107
static void uninit(int immed) {
 
108
  ALCcontext *ctx = alcGetCurrentContext();
 
109
  ALCdevice *dev = alcGetContextsDevice(ctx);
 
110
  free(tmpbuf);
 
111
  if (!immed) {
 
112
    ALint state;
 
113
    alGetSourcei(sources[0], AL_SOURCE_STATE, &state);
 
114
    while (state == AL_PLAYING) {
 
115
      usec_sleep(10000);
 
116
      alGetSourcei(sources[0], AL_SOURCE_STATE, &state);
 
117
    }
 
118
  }
 
119
  reset();
 
120
  alcMakeContextCurrent(NULL);
 
121
  alcDestroyContext(ctx);
 
122
  alcCloseDevice(dev);
 
123
}
 
124
 
 
125
static void unqueue_buffers(void) {
 
126
  ALint p;
 
127
  int s, i;
 
128
  for (s = 0;  s < ao_data.channels; s++) {
 
129
    alGetSourcei(sources[s], AL_BUFFERS_PROCESSED, &p);
 
130
    for (i = 0; i < p; i++) {
 
131
      alSourceUnqueueBuffers(sources[s], 1, &buffers[s][unqueue_buf[s]]);
 
132
      unqueue_buf[s] = (unqueue_buf[s] + 1) % NUM_BUF;
 
133
    }
 
134
  }
 
135
}
 
136
 
 
137
/**
 
138
 * \brief stop playing and empty buffers (for seeking/pause)
 
139
 */
 
140
static void reset(void) {
 
141
  alSourceRewindv(ao_data.channels, sources);
 
142
  unqueue_buffers();
 
143
}
 
144
 
 
145
/**
 
146
 * \brief stop playing, keep buffers (for pause)
 
147
 */
 
148
static void audio_pause(void) {
 
149
  alSourcePausev(ao_data.channels, sources);
 
150
}
 
151
 
 
152
/**
 
153
 * \brief resume playing, after audio_pause()
 
154
 */
 
155
static void audio_resume(void) {
 
156
  alSourcePlayv(ao_data.channels, sources);
 
157
}
 
158
 
 
159
static int get_space(void) {
 
160
  ALint queued;
 
161
  unqueue_buffers();
 
162
  alGetSourcei(sources[0], AL_BUFFERS_QUEUED, &queued);
 
163
  return (NUM_BUF - queued) * CHUNK_SIZE * ao_data.channels;
 
164
}
 
165
 
 
166
/**
 
167
 * \brief write data into buffer and reset underrun flag
 
168
 */
 
169
static int play(void *data, int len, int flags) {
 
170
  ALint state;
 
171
  int i, j, k;
 
172
  int ch;
 
173
  int16_t *d = data;
 
174
  len /= ao_data.outburst;
 
175
  for (i = 0; i < len; i++) {
 
176
    for (ch = 0; ch < ao_data.channels; ch++) {
 
177
      for (j = 0, k = ch; j < CHUNK_SIZE / 2; j++, k += ao_data.channels)
 
178
        tmpbuf[j] = d[k];
 
179
      alBufferData(buffers[ch][cur_buf[ch]], AL_FORMAT_MONO16, tmpbuf,
 
180
                     CHUNK_SIZE, ao_data.samplerate);
 
181
      alSourceQueueBuffers(sources[ch], 1, &buffers[ch][cur_buf[ch]]);
 
182
      cur_buf[ch] = (cur_buf[ch] + 1) % NUM_BUF;
 
183
    }
 
184
    d += ao_data.channels * CHUNK_SIZE / 2;
 
185
  }
 
186
  alGetSourcei(sources[0], AL_SOURCE_STATE, &state);
 
187
  if (state != AL_PLAYING) // checked here in case of an underrun
 
188
    alSourcePlayv(ao_data.channels, sources);
 
189
  return len * ao_data.outburst;
 
190
}
 
191
 
 
192
static float get_delay(void) {
 
193
  ALint queued;
 
194
  unqueue_buffers();
 
195
  alGetSourcei(sources[0], AL_BUFFERS_QUEUED, &queued);
 
196
  return queued * CHUNK_SIZE / 2 / (float)ao_data.samplerate;
 
197
}
 
198