~ubuntu-branches/ubuntu/utopic/openal-soft/utopic

« back to all changes in this revision

Viewing changes to Alc/pulseaudio.c

  • Committer: Package Import Robot
  • Author(s): Michael Terry
  • Date: 2012-05-22 10:14:53 UTC
  • mfrom: (7.1.9 sid)
  • Revision ID: package-import@ubuntu.com-20120522101453-knsv1m1m8vl5ccfp
Tags: 1:1.14-3ubuntu1
* Merge from Debian testing.  Remaining changes:
  - Add a symbols file for libopenal1
* debian/libopenal1.symbols:
  - Update for 1.14

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 * OpenAL cross platform audio library
3
 
 * Copyright (C) 2009 by Konstantinos Natsakis <konstantinos.natsakis@gmail.com>
4
 
 * Copyright (C) 2010 by Chris Robinson <chris.kcat@gmail.com>
5
 
 * This library is free software; you can redistribute it and/or
6
 
 *  modify it under the terms of the GNU Library General Public
7
 
 *  License as published by the Free Software Foundation; either
8
 
 *  version 2 of the License, or (at your option) any later version.
9
 
 *
10
 
 * This library is distributed in the hope that it will be useful,
11
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 
 *  Library General Public License for more details.
14
 
 *
15
 
 * You should have received a copy of the GNU Library General Public
16
 
 *  License along with this library; if not, write to the
17
 
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
 
 *  Boston, MA  02111-1307, USA.
19
 
 * Or go to http://www.gnu.org/copyleft/lgpl.html
20
 
 */
21
 
 
22
 
#include "config.h"
23
 
 
24
 
#include "alMain.h"
25
 
#ifdef HAVE_DLFCN_H
26
 
#include <dlfcn.h>
27
 
#endif
28
 
 
29
 
#include <pulse/pulseaudio.h>
30
 
 
31
 
#if PA_API_VERSION == 11
32
 
#define PA_STREAM_ADJUST_LATENCY 0x2000U
33
 
#define PA_STREAM_EARLY_REQUESTS 0x4000U
34
 
static __inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
35
 
{
36
 
    return (x == PA_STREAM_CREATING || x == PA_STREAM_READY);
37
 
}
38
 
static __inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
39
 
{
40
 
    return (x == PA_CONTEXT_CONNECTING || x == PA_CONTEXT_AUTHORIZING ||
41
 
            x == PA_CONTEXT_SETTING_NAME || x == PA_CONTEXT_READY);
42
 
}
43
 
#define PA_STREAM_IS_GOOD PA_STREAM_IS_GOOD
44
 
#define PA_CONTEXT_IS_GOOD PA_CONTEXT_IS_GOOD
45
 
#elif PA_API_VERSION != 12
46
 
#error Invalid PulseAudio API version
47
 
#endif
48
 
 
49
 
#ifndef PA_CHECK_VERSION
50
 
#define PA_CHECK_VERSION(major,minor,micro)                             \
51
 
    ((PA_MAJOR > (major)) ||                                            \
52
 
     (PA_MAJOR == (major) && PA_MINOR > (minor)) ||                     \
53
 
     (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro)))
54
 
#endif
55
 
 
56
 
static void *pa_handle;
57
 
#define MAKE_FUNC(x) static typeof(x) * p##x
58
 
MAKE_FUNC(pa_context_unref);
59
 
MAKE_FUNC(pa_sample_spec_valid);
60
 
MAKE_FUNC(pa_stream_drop);
61
 
MAKE_FUNC(pa_strerror);
62
 
MAKE_FUNC(pa_context_get_state);
63
 
MAKE_FUNC(pa_stream_get_state);
64
 
MAKE_FUNC(pa_threaded_mainloop_signal);
65
 
MAKE_FUNC(pa_stream_peek);
66
 
MAKE_FUNC(pa_threaded_mainloop_wait);
67
 
MAKE_FUNC(pa_threaded_mainloop_unlock);
68
 
MAKE_FUNC(pa_threaded_mainloop_in_thread);
69
 
MAKE_FUNC(pa_context_new);
70
 
MAKE_FUNC(pa_threaded_mainloop_stop);
71
 
MAKE_FUNC(pa_context_disconnect);
72
 
MAKE_FUNC(pa_threaded_mainloop_start);
73
 
MAKE_FUNC(pa_threaded_mainloop_get_api);
74
 
MAKE_FUNC(pa_context_set_state_callback);
75
 
MAKE_FUNC(pa_stream_write);
76
 
MAKE_FUNC(pa_xfree);
77
 
MAKE_FUNC(pa_stream_connect_record);
78
 
MAKE_FUNC(pa_stream_connect_playback);
79
 
MAKE_FUNC(pa_stream_readable_size);
80
 
MAKE_FUNC(pa_stream_writable_size);
81
 
MAKE_FUNC(pa_stream_cork);
82
 
MAKE_FUNC(pa_stream_is_suspended);
83
 
MAKE_FUNC(pa_stream_get_device_name);
84
 
MAKE_FUNC(pa_path_get_filename);
85
 
MAKE_FUNC(pa_get_binary_name);
86
 
MAKE_FUNC(pa_threaded_mainloop_free);
87
 
MAKE_FUNC(pa_context_errno);
88
 
MAKE_FUNC(pa_xmalloc);
89
 
MAKE_FUNC(pa_stream_unref);
90
 
MAKE_FUNC(pa_threaded_mainloop_accept);
91
 
MAKE_FUNC(pa_stream_set_write_callback);
92
 
MAKE_FUNC(pa_threaded_mainloop_new);
93
 
MAKE_FUNC(pa_context_connect);
94
 
MAKE_FUNC(pa_stream_set_buffer_attr);
95
 
MAKE_FUNC(pa_stream_get_buffer_attr);
96
 
MAKE_FUNC(pa_stream_get_sample_spec);
97
 
MAKE_FUNC(pa_stream_get_time);
98
 
MAKE_FUNC(pa_stream_set_read_callback);
99
 
MAKE_FUNC(pa_stream_set_state_callback);
100
 
MAKE_FUNC(pa_stream_set_moved_callback);
101
 
MAKE_FUNC(pa_stream_set_underflow_callback);
102
 
MAKE_FUNC(pa_stream_new);
103
 
MAKE_FUNC(pa_stream_disconnect);
104
 
MAKE_FUNC(pa_threaded_mainloop_lock);
105
 
MAKE_FUNC(pa_channel_map_init_auto);
106
 
MAKE_FUNC(pa_channel_map_parse);
107
 
MAKE_FUNC(pa_channel_map_snprint);
108
 
MAKE_FUNC(pa_channel_map_equal);
109
 
MAKE_FUNC(pa_context_get_server_info);
110
 
MAKE_FUNC(pa_context_get_sink_info_by_name);
111
 
MAKE_FUNC(pa_context_get_sink_info_list);
112
 
MAKE_FUNC(pa_context_get_source_info_list);
113
 
MAKE_FUNC(pa_operation_get_state);
114
 
MAKE_FUNC(pa_operation_unref);
115
 
#if PA_CHECK_VERSION(0,9,15)
116
 
MAKE_FUNC(pa_channel_map_superset);
117
 
MAKE_FUNC(pa_stream_set_buffer_attr_callback);
118
 
#endif
119
 
#if PA_CHECK_VERSION(0,9,16)
120
 
MAKE_FUNC(pa_stream_begin_write);
121
 
#endif
122
 
#undef MAKE_FUNC
123
 
 
124
 
#ifndef PATH_MAX
125
 
#define PATH_MAX 4096
126
 
#endif
127
 
 
128
 
typedef struct {
129
 
    char *device_name;
130
 
 
131
 
    ALCuint samples;
132
 
    ALCuint frame_size;
133
 
 
134
 
    RingBuffer *ring;
135
 
 
136
 
    pa_buffer_attr attr;
137
 
    pa_sample_spec spec;
138
 
 
139
 
    pa_threaded_mainloop *loop;
140
 
 
141
 
    ALvoid *thread;
142
 
    volatile ALboolean killNow;
143
 
 
144
 
    pa_stream *stream;
145
 
    pa_context *context;
146
 
} pulse_data;
147
 
 
148
 
typedef struct {
149
 
    char *name;
150
 
    char *device_name;
151
 
} DevMap;
152
 
 
153
 
 
154
 
static const ALCchar pulse_device[] = "PulseAudio Default";
155
 
static DevMap *allDevNameMap;
156
 
static ALuint numDevNames;
157
 
static DevMap *allCaptureDevNameMap;
158
 
static ALuint numCaptureDevNames;
159
 
static pa_context_flags_t pulse_ctx_flags;
160
 
 
161
 
 
162
 
void *pulse_load(void) //{{{
163
 
{
164
 
    if(!pa_handle)
165
 
    {
166
 
#ifdef _WIN32
167
 
        pa_handle = LoadLibrary("libpulse-0.dll");
168
 
#define LOAD_FUNC(x) do { \
169
 
    p##x = (typeof(p##x))GetProcAddress(pa_handle, #x); \
170
 
    if(!(p##x)) { \
171
 
        AL_PRINT("Could not load %s from libpulse-0.dll\n", #x); \
172
 
        FreeLibrary(pa_handle); \
173
 
        pa_handle = NULL; \
174
 
        return NULL; \
175
 
    } \
176
 
} while(0)
177
 
#define LOAD_OPTIONAL_FUNC(x) do { \
178
 
    p##x = (typeof(p##x))GetProcAddress(pa_handle, #x); \
179
 
} while(0)
180
 
 
181
 
#elif defined (HAVE_DLFCN_H)
182
 
 
183
 
        const char *err;
184
 
#if defined(__APPLE__) && defined(__MACH__)
185
 
        pa_handle = dlopen("libpulse.0.dylib", RTLD_NOW);
186
 
#else
187
 
        pa_handle = dlopen("libpulse.so.0", RTLD_NOW);
188
 
#endif
189
 
        dlerror();
190
 
 
191
 
#define LOAD_FUNC(x) do { \
192
 
    p##x = dlsym(pa_handle, #x); \
193
 
    if((err=dlerror()) != NULL) { \
194
 
        AL_PRINT("Could not load %s from libpulse: %s\n", #x, err); \
195
 
        dlclose(pa_handle); \
196
 
        pa_handle = NULL; \
197
 
        return NULL; \
198
 
    } \
199
 
} while(0)
200
 
#define LOAD_OPTIONAL_FUNC(x) do { \
201
 
    p##x = dlsym(pa_handle, #x); \
202
 
    if((err=dlerror()) != NULL) { \
203
 
        p##x = NULL; \
204
 
    } \
205
 
} while(0)
206
 
 
207
 
#else
208
 
 
209
 
        pa_handle = (void*)0xDEADBEEF;
210
 
#define LOAD_FUNC(x) p##x = (x)
211
 
#define LOAD_OPTIONAL_FUNC(x) p##x = (x)
212
 
 
213
 
#endif
214
 
        if(!pa_handle)
215
 
            return NULL;
216
 
 
217
 
LOAD_FUNC(pa_context_unref);
218
 
LOAD_FUNC(pa_sample_spec_valid);
219
 
LOAD_FUNC(pa_stream_drop);
220
 
LOAD_FUNC(pa_strerror);
221
 
LOAD_FUNC(pa_context_get_state);
222
 
LOAD_FUNC(pa_stream_get_state);
223
 
LOAD_FUNC(pa_threaded_mainloop_signal);
224
 
LOAD_FUNC(pa_stream_peek);
225
 
LOAD_FUNC(pa_threaded_mainloop_wait);
226
 
LOAD_FUNC(pa_threaded_mainloop_unlock);
227
 
LOAD_FUNC(pa_threaded_mainloop_in_thread);
228
 
LOAD_FUNC(pa_context_new);
229
 
LOAD_FUNC(pa_threaded_mainloop_stop);
230
 
LOAD_FUNC(pa_context_disconnect);
231
 
LOAD_FUNC(pa_threaded_mainloop_start);
232
 
LOAD_FUNC(pa_threaded_mainloop_get_api);
233
 
LOAD_FUNC(pa_context_set_state_callback);
234
 
LOAD_FUNC(pa_stream_write);
235
 
LOAD_FUNC(pa_xfree);
236
 
LOAD_FUNC(pa_stream_connect_record);
237
 
LOAD_FUNC(pa_stream_connect_playback);
238
 
LOAD_FUNC(pa_stream_readable_size);
239
 
LOAD_FUNC(pa_stream_writable_size);
240
 
LOAD_FUNC(pa_stream_cork);
241
 
LOAD_FUNC(pa_stream_is_suspended);
242
 
LOAD_FUNC(pa_stream_get_device_name);
243
 
LOAD_FUNC(pa_path_get_filename);
244
 
LOAD_FUNC(pa_get_binary_name);
245
 
LOAD_FUNC(pa_threaded_mainloop_free);
246
 
LOAD_FUNC(pa_context_errno);
247
 
LOAD_FUNC(pa_xmalloc);
248
 
LOAD_FUNC(pa_stream_unref);
249
 
LOAD_FUNC(pa_threaded_mainloop_accept);
250
 
LOAD_FUNC(pa_stream_set_write_callback);
251
 
LOAD_FUNC(pa_threaded_mainloop_new);
252
 
LOAD_FUNC(pa_context_connect);
253
 
LOAD_FUNC(pa_stream_set_buffer_attr);
254
 
LOAD_FUNC(pa_stream_get_buffer_attr);
255
 
LOAD_FUNC(pa_stream_get_sample_spec);
256
 
LOAD_FUNC(pa_stream_get_time);
257
 
LOAD_FUNC(pa_stream_set_read_callback);
258
 
LOAD_FUNC(pa_stream_set_state_callback);
259
 
LOAD_FUNC(pa_stream_set_moved_callback);
260
 
LOAD_FUNC(pa_stream_set_underflow_callback);
261
 
LOAD_FUNC(pa_stream_new);
262
 
LOAD_FUNC(pa_stream_disconnect);
263
 
LOAD_FUNC(pa_threaded_mainloop_lock);
264
 
LOAD_FUNC(pa_channel_map_init_auto);
265
 
LOAD_FUNC(pa_channel_map_parse);
266
 
LOAD_FUNC(pa_channel_map_snprint);
267
 
LOAD_FUNC(pa_channel_map_equal);
268
 
LOAD_FUNC(pa_context_get_server_info);
269
 
LOAD_FUNC(pa_context_get_sink_info_by_name);
270
 
LOAD_FUNC(pa_context_get_sink_info_list);
271
 
LOAD_FUNC(pa_context_get_source_info_list);
272
 
LOAD_FUNC(pa_operation_get_state);
273
 
LOAD_FUNC(pa_operation_unref);
274
 
#if PA_CHECK_VERSION(0,9,15)
275
 
LOAD_OPTIONAL_FUNC(pa_channel_map_superset);
276
 
LOAD_OPTIONAL_FUNC(pa_stream_set_buffer_attr_callback);
277
 
#endif
278
 
#if PA_CHECK_VERSION(0,9,16)
279
 
LOAD_OPTIONAL_FUNC(pa_stream_begin_write);
280
 
#endif
281
 
 
282
 
#undef LOAD_OPTIONAL_FUNC
283
 
#undef LOAD_FUNC
284
 
    }
285
 
    return pa_handle;
286
 
} //}}}
287
 
 
288
 
// PulseAudio Event Callbacks //{{{
289
 
static void context_state_callback(pa_context *context, void *pdata) //{{{
290
 
{
291
 
    pa_threaded_mainloop *loop = pdata;
292
 
    pa_context_state_t state;
293
 
 
294
 
    state = ppa_context_get_state(context);
295
 
    if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state))
296
 
        ppa_threaded_mainloop_signal(loop, 0);
297
 
}//}}}
298
 
 
299
 
static void stream_state_callback(pa_stream *stream, void *pdata) //{{{
300
 
{
301
 
    pa_threaded_mainloop *loop = pdata;
302
 
    pa_stream_state_t state;
303
 
 
304
 
    state = ppa_stream_get_state(stream);
305
 
    if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state))
306
 
        ppa_threaded_mainloop_signal(loop, 0);
307
 
}//}}}
308
 
 
309
 
static void stream_signal_callback(pa_stream *stream, void *pdata) //{{{
310
 
{
311
 
    ALCdevice *Device = pdata;
312
 
    pulse_data *data = Device->ExtraData;
313
 
    (void)stream;
314
 
 
315
 
    ppa_threaded_mainloop_signal(data->loop, 0);
316
 
}//}}}
317
 
 
318
 
static void stream_buffer_attr_callback(pa_stream *stream, void *pdata) //{{{
319
 
{
320
 
    ALCdevice *Device = pdata;
321
 
    pulse_data *data = Device->ExtraData;
322
 
 
323
 
    SuspendContext(NULL);
324
 
 
325
 
    data->attr = *(ppa_stream_get_buffer_attr(stream));
326
 
    Device->UpdateSize = data->attr.minreq / data->frame_size;
327
 
    Device->NumUpdates = (data->attr.tlength/data->frame_size) / Device->UpdateSize;
328
 
    if(Device->NumUpdates <= 1)
329
 
    {
330
 
        Device->NumUpdates = 1;
331
 
        AL_PRINT("PulseAudio returned minreq > tlength/2; expect break up\n");
332
 
    }
333
 
 
334
 
    ProcessContext(NULL);
335
 
}//}}}
336
 
 
337
 
static void stream_device_callback(pa_stream *stream, void *pdata) //{{{
338
 
{
339
 
    ALCdevice *Device = pdata;
340
 
    pulse_data *data = Device->ExtraData;
341
 
 
342
 
    free(data->device_name);
343
 
    data->device_name = strdup(ppa_stream_get_device_name(stream));
344
 
}//}}}
345
 
 
346
 
static void context_state_callback2(pa_context *context, void *pdata) //{{{
347
 
{
348
 
    ALCdevice *Device = pdata;
349
 
    pulse_data *data = Device->ExtraData;
350
 
 
351
 
    if(ppa_context_get_state(context) == PA_CONTEXT_FAILED)
352
 
    {
353
 
        AL_PRINT("Received context failure!\n");
354
 
        aluHandleDisconnect(Device);
355
 
    }
356
 
    ppa_threaded_mainloop_signal(data->loop, 0);
357
 
}//}}}
358
 
 
359
 
static void stream_state_callback2(pa_stream *stream, void *pdata) //{{{
360
 
{
361
 
    ALCdevice *Device = pdata;
362
 
    pulse_data *data = Device->ExtraData;
363
 
 
364
 
    if(ppa_stream_get_state(stream) == PA_STREAM_FAILED)
365
 
    {
366
 
        AL_PRINT("Received stream failure!\n");
367
 
        aluHandleDisconnect(Device);
368
 
    }
369
 
    ppa_threaded_mainloop_signal(data->loop, 0);
370
 
}//}}}
371
 
 
372
 
static void stream_success_callback(pa_stream *stream, int success, void *pdata) //{{{
373
 
{
374
 
    ALCdevice *Device = pdata;
375
 
    pulse_data *data = Device->ExtraData;
376
 
    (void)stream;
377
 
    (void)success;
378
 
 
379
 
    ppa_threaded_mainloop_signal(data->loop, 0);
380
 
}//}}}
381
 
 
382
 
static void sink_info_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata) //{{{
383
 
{
384
 
    ALCdevice *device = pdata;
385
 
    pulse_data *data = device->ExtraData;
386
 
    char chanmap_str[256] = "";
387
 
    const struct {
388
 
        const char *str;
389
 
        enum DevFmtChannels chans;
390
 
    } chanmaps[] = {
391
 
        { "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right",
392
 
          DevFmtX71 },
393
 
        { "front-left,front-right,front-center,lfe,rear-center,side-left,side-right",
394
 
          DevFmtX61 },
395
 
        { "front-left,front-right,front-center,lfe,rear-left,rear-right",
396
 
          DevFmtX51 },
397
 
        { "front-left,front-right,rear-left,rear-right", DevFmtQuad },
398
 
        { "front-left,front-right", DevFmtStereo },
399
 
        { "mono", DevFmtMono },
400
 
        { NULL, 0 }
401
 
    };
402
 
    int i;
403
 
    (void)context;
404
 
 
405
 
    if(eol)
406
 
    {
407
 
        ppa_threaded_mainloop_signal(data->loop, 0);
408
 
        return;
409
 
    }
410
 
 
411
 
    for(i = 0;chanmaps[i].str;i++)
412
 
    {
413
 
        pa_channel_map map;
414
 
        if(!ppa_channel_map_parse(&map, chanmaps[i].str))
415
 
            continue;
416
 
 
417
 
        if(ppa_channel_map_equal(&info->channel_map, &map)
418
 
#if PA_CHECK_VERSION(0,9,15)
419
 
           || (ppa_channel_map_superset &&
420
 
               ppa_channel_map_superset(&info->channel_map, &map))
421
 
#endif
422
 
            )
423
 
        {
424
 
            device->FmtChans = chanmaps[i].chans;
425
 
            return;
426
 
        }
427
 
    }
428
 
 
429
 
    ppa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
430
 
    AL_PRINT("Failed to find format for channel map:\n    %s\n", chanmap_str);
431
 
}//}}}
432
 
 
433
 
static void sink_device_callback(pa_context *context, const pa_sink_info *info, int eol, void *pdata) //{{{
434
 
{
435
 
    pa_threaded_mainloop *loop = pdata;
436
 
    char str[1024];
437
 
    void *temp;
438
 
    int count;
439
 
    ALuint i;
440
 
 
441
 
    (void)context;
442
 
 
443
 
    if(eol)
444
 
    {
445
 
        ppa_threaded_mainloop_signal(loop, 0);
446
 
        return;
447
 
    }
448
 
 
449
 
    count = 0;
450
 
    do {
451
 
        if(count == 0)
452
 
            snprintf(str, sizeof(str), "%s via PulseAudio", info->description);
453
 
        else
454
 
            snprintf(str, sizeof(str), "%s #%d via PulseAudio", info->description, count+1);
455
 
        count++;
456
 
 
457
 
        for(i = 0;i < numDevNames;i++)
458
 
        {
459
 
            if(strcmp(str, allDevNameMap[i].name) == 0)
460
 
                break;
461
 
        }
462
 
    } while(i != numDevNames);
463
 
 
464
 
    temp = realloc(allDevNameMap, (numDevNames+1) * sizeof(*allDevNameMap));
465
 
    if(temp)
466
 
    {
467
 
        allDevNameMap = temp;
468
 
        allDevNameMap[numDevNames].name = strdup(str);
469
 
        allDevNameMap[numDevNames].device_name = strdup(info->name);
470
 
        numDevNames++;
471
 
    }
472
 
}//}}}
473
 
 
474
 
static void source_device_callback(pa_context *context, const pa_source_info *info, int eol, void *pdata) //{{{
475
 
{
476
 
    pa_threaded_mainloop *loop = pdata;
477
 
    char str[1024];
478
 
    void *temp;
479
 
    int count;
480
 
    ALuint i;
481
 
 
482
 
    (void)context;
483
 
 
484
 
    if(eol)
485
 
    {
486
 
        ppa_threaded_mainloop_signal(loop, 0);
487
 
        return;
488
 
    }
489
 
 
490
 
    count = 0;
491
 
    do {
492
 
        if(count == 0)
493
 
            snprintf(str, sizeof(str), "%s via PulseAudio", info->description);
494
 
        else
495
 
            snprintf(str, sizeof(str), "%s #%d via PulseAudio", info->description, count+1);
496
 
        count++;
497
 
 
498
 
        for(i = 0;i < numCaptureDevNames;i++)
499
 
        {
500
 
            if(strcmp(str, allCaptureDevNameMap[i].name) == 0)
501
 
                break;
502
 
        }
503
 
    } while(i != numCaptureDevNames);
504
 
 
505
 
    temp = realloc(allCaptureDevNameMap, (numCaptureDevNames+1) * sizeof(*allCaptureDevNameMap));
506
 
    if(temp)
507
 
    {
508
 
        allCaptureDevNameMap = temp;
509
 
        allCaptureDevNameMap[numCaptureDevNames].name = strdup(str);
510
 
        allCaptureDevNameMap[numCaptureDevNames].device_name = strdup(info->name);
511
 
        numCaptureDevNames++;
512
 
    }
513
 
}//}}}
514
 
//}}}
515
 
 
516
 
// PulseAudio I/O Callbacks //{{{
517
 
static void stream_write_callback(pa_stream *stream, size_t len, void *pdata) //{{{
518
 
{
519
 
    ALCdevice *Device = pdata;
520
 
    pulse_data *data = Device->ExtraData;
521
 
    (void)stream;
522
 
    (void)len;
523
 
 
524
 
    ppa_threaded_mainloop_signal(data->loop, 0);
525
 
} //}}}
526
 
//}}}
527
 
 
528
 
static ALuint PulseProc(ALvoid *param)
529
 
{
530
 
    ALCdevice *Device = param;
531
 
    pulse_data *data = Device->ExtraData;
532
 
    ssize_t len;
533
 
 
534
 
    SetRTPriority();
535
 
 
536
 
    ppa_threaded_mainloop_lock(data->loop);
537
 
    do {
538
 
        len = (Device->Connected ? ppa_stream_writable_size(data->stream) : 0);
539
 
        len -= len%(Device->UpdateSize*data->frame_size);
540
 
        if(len == 0)
541
 
        {
542
 
            ppa_threaded_mainloop_wait(data->loop);
543
 
            continue;
544
 
        }
545
 
 
546
 
        while(len > 0)
547
 
        {
548
 
            size_t newlen = len;
549
 
            void *buf;
550
 
            pa_free_cb_t free_func = NULL;
551
 
 
552
 
#if PA_CHECK_VERSION(0,9,16)
553
 
            if(!ppa_stream_begin_write ||
554
 
               ppa_stream_begin_write(data->stream, &buf, &newlen) < 0)
555
 
#endif
556
 
            {
557
 
                buf = ppa_xmalloc(newlen);
558
 
                free_func = ppa_xfree;
559
 
            }
560
 
            ppa_threaded_mainloop_unlock(data->loop);
561
 
 
562
 
            aluMixData(Device, buf, newlen/data->frame_size);
563
 
 
564
 
            ppa_threaded_mainloop_lock(data->loop);
565
 
            ppa_stream_write(data->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE);
566
 
            len -= newlen;
567
 
        }
568
 
    } while(Device->Connected && !data->killNow);
569
 
    ppa_threaded_mainloop_unlock(data->loop);
570
 
 
571
 
    return 0;
572
 
}
573
 
 
574
 
static pa_context *connect_context(pa_threaded_mainloop *loop)
575
 
{
576
 
    const char *name = "OpenAL Soft";
577
 
    char path_name[PATH_MAX];
578
 
    pa_context_state_t state;
579
 
    pa_context *context;
580
 
    int err;
581
 
 
582
 
    if(ppa_get_binary_name(path_name, sizeof(path_name)))
583
 
        name = ppa_path_get_filename(path_name);
584
 
 
585
 
    context = ppa_context_new(ppa_threaded_mainloop_get_api(loop), name);
586
 
    if(!context)
587
 
    {
588
 
        AL_PRINT("pa_context_new() failed\n");
589
 
        return NULL;
590
 
    }
591
 
 
592
 
    ppa_context_set_state_callback(context, context_state_callback, loop);
593
 
 
594
 
    if((err=ppa_context_connect(context, NULL, pulse_ctx_flags, NULL)) >= 0)
595
 
    {
596
 
        while((state=ppa_context_get_state(context)) != PA_CONTEXT_READY)
597
 
        {
598
 
            if(!PA_CONTEXT_IS_GOOD(state))
599
 
            {
600
 
                err = ppa_context_errno(context);
601
 
                if(err > 0)  err = -err;
602
 
                break;
603
 
            }
604
 
 
605
 
            ppa_threaded_mainloop_wait(loop);
606
 
        }
607
 
    }
608
 
    ppa_context_set_state_callback(context, NULL, NULL);
609
 
 
610
 
    if(err < 0)
611
 
    {
612
 
        AL_PRINT("Context did not connect: %s\n", ppa_strerror(err));
613
 
        ppa_context_unref(context);
614
 
        return NULL;
615
 
    }
616
 
 
617
 
    return context;
618
 
}
619
 
 
620
 
static pa_stream *connect_playback_stream(ALCdevice *device,
621
 
    pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
622
 
    pa_channel_map *chanmap)
623
 
{
624
 
    pulse_data *data = device->ExtraData;
625
 
    pa_stream_state_t state;
626
 
    pa_stream *stream;
627
 
 
628
 
    stream = ppa_stream_new(data->context, "Playback Stream", spec, chanmap);
629
 
    if(!stream)
630
 
    {
631
 
        AL_PRINT("pa_stream_new() failed: %s\n",
632
 
                 ppa_strerror(ppa_context_errno(data->context)));
633
 
        return NULL;
634
 
    }
635
 
 
636
 
    ppa_stream_set_state_callback(stream, stream_state_callback, data->loop);
637
 
 
638
 
    if(ppa_stream_connect_playback(stream, data->device_name, attr, flags, NULL, NULL) < 0)
639
 
    {
640
 
        AL_PRINT("Stream did not connect: %s\n",
641
 
                 ppa_strerror(ppa_context_errno(data->context)));
642
 
        ppa_stream_unref(stream);
643
 
        return NULL;
644
 
    }
645
 
 
646
 
    while((state=ppa_stream_get_state(stream)) != PA_STREAM_READY)
647
 
    {
648
 
        if(!PA_STREAM_IS_GOOD(state))
649
 
        {
650
 
            AL_PRINT("Stream did not get ready: %s\n",
651
 
                     ppa_strerror(ppa_context_errno(data->context)));
652
 
            ppa_stream_unref(stream);
653
 
            return NULL;
654
 
        }
655
 
 
656
 
        ppa_threaded_mainloop_wait(data->loop);
657
 
    }
658
 
    ppa_stream_set_state_callback(stream, NULL, NULL);
659
 
 
660
 
    return stream;
661
 
}
662
 
 
663
 
static void probe_devices(ALboolean capture)
664
 
{
665
 
    pa_threaded_mainloop *loop;
666
 
 
667
 
    if(capture == AL_FALSE)
668
 
        allDevNameMap = malloc(sizeof(DevMap) * 1);
669
 
    else
670
 
        allCaptureDevNameMap = malloc(sizeof(DevMap) * 1);
671
 
 
672
 
    if((loop=ppa_threaded_mainloop_new()) &&
673
 
       ppa_threaded_mainloop_start(loop) >= 0)
674
 
    {
675
 
        pa_context *context;
676
 
 
677
 
        ppa_threaded_mainloop_lock(loop);
678
 
        context = connect_context(loop);
679
 
        if(context)
680
 
        {
681
 
            pa_operation *o;
682
 
 
683
 
            if(capture == AL_FALSE)
684
 
            {
685
 
                allDevNameMap[0].name = strdup(pulse_device);
686
 
                allDevNameMap[0].device_name = NULL;
687
 
                numDevNames = 1;
688
 
 
689
 
                o = ppa_context_get_sink_info_list(context, sink_device_callback, loop);
690
 
            }
691
 
            else
692
 
            {
693
 
                allCaptureDevNameMap[0].name = strdup(pulse_device);
694
 
                allCaptureDevNameMap[0].device_name = NULL;
695
 
                numCaptureDevNames = 1;
696
 
 
697
 
                o = ppa_context_get_source_info_list(context, source_device_callback, loop);
698
 
            }
699
 
            while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
700
 
                ppa_threaded_mainloop_wait(loop);
701
 
            ppa_operation_unref(o);
702
 
 
703
 
            ppa_context_disconnect(context);
704
 
            ppa_context_unref(context);
705
 
        }
706
 
        ppa_threaded_mainloop_unlock(loop);
707
 
        ppa_threaded_mainloop_stop(loop);
708
 
    }
709
 
    if(loop)
710
 
        ppa_threaded_mainloop_free(loop);
711
 
}
712
 
 
713
 
 
714
 
static ALCboolean pulse_open(ALCdevice *device, const ALCchar *device_name) //{{{
715
 
{
716
 
    pulse_data *data = ppa_xmalloc(sizeof(pulse_data));
717
 
    memset(data, 0, sizeof(*data));
718
 
 
719
 
    if(!(data->loop = ppa_threaded_mainloop_new()))
720
 
    {
721
 
        AL_PRINT("pa_threaded_mainloop_new() failed!\n");
722
 
        goto out;
723
 
    }
724
 
    if(ppa_threaded_mainloop_start(data->loop) < 0)
725
 
    {
726
 
        AL_PRINT("pa_threaded_mainloop_start() failed\n");
727
 
        goto out;
728
 
    }
729
 
 
730
 
    ppa_threaded_mainloop_lock(data->loop);
731
 
    device->ExtraData = data;
732
 
 
733
 
    data->context = connect_context(data->loop);
734
 
    if(!data->context)
735
 
    {
736
 
        ppa_threaded_mainloop_unlock(data->loop);
737
 
        goto out;
738
 
    }
739
 
    ppa_context_set_state_callback(data->context, context_state_callback2, device);
740
 
 
741
 
    device->szDeviceName = strdup(device_name);
742
 
 
743
 
    ppa_threaded_mainloop_unlock(data->loop);
744
 
    return ALC_TRUE;
745
 
 
746
 
out:
747
 
    if(data->loop)
748
 
    {
749
 
        ppa_threaded_mainloop_stop(data->loop);
750
 
        ppa_threaded_mainloop_free(data->loop);
751
 
    }
752
 
 
753
 
    device->ExtraData = NULL;
754
 
    ppa_xfree(data);
755
 
    return ALC_FALSE;
756
 
} //}}}
757
 
 
758
 
static void pulse_close(ALCdevice *device) //{{{
759
 
{
760
 
    pulse_data *data = device->ExtraData;
761
 
 
762
 
    ppa_threaded_mainloop_lock(data->loop);
763
 
 
764
 
    if(data->stream)
765
 
    {
766
 
        ppa_stream_disconnect(data->stream);
767
 
        ppa_stream_unref(data->stream);
768
 
    }
769
 
 
770
 
    ppa_context_disconnect(data->context);
771
 
    ppa_context_unref(data->context);
772
 
 
773
 
    ppa_threaded_mainloop_unlock(data->loop);
774
 
 
775
 
    ppa_threaded_mainloop_stop(data->loop);
776
 
    ppa_threaded_mainloop_free(data->loop);
777
 
 
778
 
    DestroyRingBuffer(data->ring);
779
 
    free(data->device_name);
780
 
 
781
 
    device->ExtraData = NULL;
782
 
    ppa_xfree(data);
783
 
} //}}}
784
 
//}}}
785
 
 
786
 
// OpenAL {{{
787
 
static ALCboolean pulse_open_playback(ALCdevice *device, const ALCchar *device_name) //{{{
788
 
{
789
 
    char *pulse_name = NULL;
790
 
    pa_sample_spec spec;
791
 
    pulse_data *data;
792
 
 
793
 
    if(!pulse_load())
794
 
        return ALC_FALSE;
795
 
 
796
 
    if(!allDevNameMap)
797
 
        probe_devices(AL_FALSE);
798
 
 
799
 
    if(!device_name && numDevNames > 0)
800
 
        device_name = allDevNameMap[0].name;
801
 
    else
802
 
    {
803
 
        ALuint i;
804
 
 
805
 
        for(i = 0;i < numDevNames;i++)
806
 
        {
807
 
            if(strcmp(device_name, allDevNameMap[i].name) == 0)
808
 
            {
809
 
                pulse_name = allDevNameMap[i].device_name;
810
 
                break;
811
 
            }
812
 
        }
813
 
        if(i == numDevNames)
814
 
            return ALC_FALSE;
815
 
    }
816
 
 
817
 
    if(pulse_open(device, device_name) == ALC_FALSE)
818
 
        return ALC_FALSE;
819
 
 
820
 
    data = device->ExtraData;
821
 
 
822
 
    ppa_threaded_mainloop_lock(data->loop);
823
 
 
824
 
    spec.format = PA_SAMPLE_S16NE;
825
 
    spec.rate = 44100;
826
 
    spec.channels = 2;
827
 
 
828
 
    data->device_name = pulse_name;
829
 
    pa_stream *stream = connect_playback_stream(device, 0, NULL, &spec, NULL);
830
 
    if(!stream)
831
 
    {
832
 
        ppa_threaded_mainloop_unlock(data->loop);
833
 
        goto fail;
834
 
    }
835
 
 
836
 
    if(ppa_stream_is_suspended(stream))
837
 
    {
838
 
        AL_PRINT("Device is suspended\n");
839
 
        ppa_stream_disconnect(stream);
840
 
        ppa_stream_unref(stream);
841
 
        ppa_threaded_mainloop_unlock(data->loop);
842
 
        goto fail;
843
 
    }
844
 
    data->device_name = strdup(ppa_stream_get_device_name(stream));
845
 
 
846
 
    ppa_stream_disconnect(stream);
847
 
    ppa_stream_unref(stream);
848
 
 
849
 
    ppa_threaded_mainloop_unlock(data->loop);
850
 
 
851
 
    return ALC_TRUE;
852
 
 
853
 
fail:
854
 
    pulse_close(device);
855
 
    return ALC_FALSE;
856
 
} //}}}
857
 
 
858
 
static void pulse_close_playback(ALCdevice *device) //{{{
859
 
{
860
 
    pulse_close(device);
861
 
} //}}}
862
 
 
863
 
static ALCboolean pulse_reset_playback(ALCdevice *device) //{{{
864
 
{
865
 
    pulse_data *data = device->ExtraData;
866
 
    pa_stream_flags_t flags = 0;
867
 
    pa_channel_map chanmap;
868
 
 
869
 
    ppa_threaded_mainloop_lock(data->loop);
870
 
 
871
 
    if(!ConfigValueExists(NULL, "format"))
872
 
    {
873
 
        pa_operation *o;
874
 
        o = ppa_context_get_sink_info_by_name(data->context, data->device_name, sink_info_callback, device);
875
 
        while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
876
 
            ppa_threaded_mainloop_wait(data->loop);
877
 
        ppa_operation_unref(o);
878
 
    }
879
 
    if(!ConfigValueExists(NULL, "frequency"))
880
 
        flags |= PA_STREAM_FIX_RATE;
881
 
 
882
 
    data->frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
883
 
    data->attr.prebuf = -1;
884
 
    data->attr.fragsize = -1;
885
 
    data->attr.minreq = device->UpdateSize * data->frame_size;
886
 
    data->attr.tlength = data->attr.minreq * device->NumUpdates;
887
 
    if(data->attr.tlength < data->attr.minreq*2)
888
 
        data->attr.tlength = data->attr.minreq*2;
889
 
    data->attr.maxlength = data->attr.tlength;
890
 
    flags |= PA_STREAM_EARLY_REQUESTS;
891
 
    flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE;
892
 
 
893
 
    switch(device->FmtType)
894
 
    {
895
 
        case DevFmtByte:
896
 
            device->FmtType = DevFmtUByte;
897
 
            /* fall-through */
898
 
        case DevFmtUByte:
899
 
            data->spec.format = PA_SAMPLE_U8;
900
 
            break;
901
 
        case DevFmtUShort:
902
 
            device->FmtType = DevFmtShort;
903
 
            /* fall-through */
904
 
        case DevFmtShort:
905
 
            data->spec.format = PA_SAMPLE_S16NE;
906
 
            break;
907
 
        case DevFmtFloat:
908
 
            data->spec.format = PA_SAMPLE_FLOAT32NE;
909
 
            break;
910
 
    }
911
 
    data->spec.rate = device->Frequency;
912
 
    data->spec.channels = ChannelsFromDevFmt(device->FmtChans);
913
 
 
914
 
    if(ppa_sample_spec_valid(&data->spec) == 0)
915
 
    {
916
 
        AL_PRINT("Invalid sample format\n");
917
 
        ppa_threaded_mainloop_unlock(data->loop);
918
 
        return ALC_FALSE;
919
 
    }
920
 
 
921
 
    if(!ppa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
922
 
    {
923
 
        AL_PRINT("Couldn't build map for channel count (%d)!\n", data->spec.channels);
924
 
        ppa_threaded_mainloop_unlock(data->loop);
925
 
        return ALC_FALSE;
926
 
    }
927
 
    SetDefaultWFXChannelOrder(device);
928
 
 
929
 
    data->stream = connect_playback_stream(device, flags, &data->attr, &data->spec, &chanmap);
930
 
    if(!data->stream)
931
 
    {
932
 
        ppa_threaded_mainloop_unlock(data->loop);
933
 
        return ALC_FALSE;
934
 
    }
935
 
 
936
 
    ppa_stream_set_state_callback(data->stream, stream_state_callback2, device);
937
 
 
938
 
    data->spec = *(ppa_stream_get_sample_spec(data->stream));
939
 
    if(device->Frequency != data->spec.rate)
940
 
    {
941
 
        pa_operation *o;
942
 
 
943
 
        /* Server updated our playback rate, so modify the buffer attribs
944
 
         * accordingly. */
945
 
        data->attr.minreq = (ALuint64)(data->attr.minreq/data->frame_size) *
946
 
                            data->spec.rate / device->Frequency * data->frame_size;
947
 
        data->attr.tlength = data->attr.minreq * device->NumUpdates;
948
 
        data->attr.maxlength = data->attr.tlength;
949
 
 
950
 
        o = ppa_stream_set_buffer_attr(data->stream, &data->attr,
951
 
                                       stream_success_callback, device);
952
 
        while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
953
 
            ppa_threaded_mainloop_wait(data->loop);
954
 
        ppa_operation_unref(o);
955
 
 
956
 
        device->Frequency = data->spec.rate;
957
 
    }
958
 
 
959
 
    stream_buffer_attr_callback(data->stream, device);
960
 
#if PA_CHECK_VERSION(0,9,15)
961
 
    if(ppa_stream_set_buffer_attr_callback)
962
 
        ppa_stream_set_buffer_attr_callback(data->stream, stream_buffer_attr_callback, device);
963
 
#endif
964
 
    ppa_stream_set_moved_callback(data->stream, stream_device_callback, device);
965
 
    ppa_stream_set_write_callback(data->stream, stream_write_callback, device);
966
 
    ppa_stream_set_underflow_callback(data->stream, stream_signal_callback, device);
967
 
 
968
 
    data->thread = StartThread(PulseProc, device);
969
 
    if(!data->thread)
970
 
    {
971
 
#if PA_CHECK_VERSION(0,9,15)
972
 
        if(ppa_stream_set_buffer_attr_callback)
973
 
            ppa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
974
 
#endif
975
 
        ppa_stream_set_moved_callback(data->stream, NULL, NULL);
976
 
        ppa_stream_set_write_callback(data->stream, NULL, NULL);
977
 
        ppa_stream_set_underflow_callback(data->stream, NULL, NULL);
978
 
        ppa_stream_disconnect(data->stream);
979
 
        ppa_stream_unref(data->stream);
980
 
        data->stream = NULL;
981
 
 
982
 
        ppa_threaded_mainloop_unlock(data->loop);
983
 
        return ALC_FALSE;
984
 
    }
985
 
 
986
 
    ppa_threaded_mainloop_unlock(data->loop);
987
 
    return ALC_TRUE;
988
 
} //}}}
989
 
 
990
 
static void pulse_stop_playback(ALCdevice *device) //{{{
991
 
{
992
 
    pulse_data *data = device->ExtraData;
993
 
 
994
 
    if(!data->stream)
995
 
        return;
996
 
 
997
 
    data->killNow = AL_TRUE;
998
 
    if(data->thread)
999
 
    {
1000
 
        ppa_threaded_mainloop_signal(data->loop, 0);
1001
 
        StopThread(data->thread);
1002
 
        data->thread = NULL;
1003
 
    }
1004
 
    data->killNow = AL_FALSE;
1005
 
 
1006
 
    ppa_threaded_mainloop_lock(data->loop);
1007
 
 
1008
 
#if PA_CHECK_VERSION(0,9,15)
1009
 
    if(ppa_stream_set_buffer_attr_callback)
1010
 
        ppa_stream_set_buffer_attr_callback(data->stream, NULL, NULL);
1011
 
#endif
1012
 
    ppa_stream_set_moved_callback(data->stream, NULL, NULL);
1013
 
    ppa_stream_set_write_callback(data->stream, NULL, NULL);
1014
 
    ppa_stream_set_underflow_callback(data->stream, NULL, NULL);
1015
 
    ppa_stream_disconnect(data->stream);
1016
 
    ppa_stream_unref(data->stream);
1017
 
    data->stream = NULL;
1018
 
 
1019
 
    ppa_threaded_mainloop_unlock(data->loop);
1020
 
} //}}}
1021
 
 
1022
 
 
1023
 
static ALCboolean pulse_open_capture(ALCdevice *device, const ALCchar *device_name) //{{{
1024
 
{
1025
 
    char *pulse_name = NULL;
1026
 
    pulse_data *data;
1027
 
    pa_stream_flags_t flags = 0;
1028
 
    pa_stream_state_t state;
1029
 
    pa_channel_map chanmap;
1030
 
 
1031
 
    if(!pulse_load())
1032
 
        return ALC_FALSE;
1033
 
 
1034
 
    if(!allCaptureDevNameMap)
1035
 
        probe_devices(AL_TRUE);
1036
 
 
1037
 
    if(!device_name && numCaptureDevNames > 0)
1038
 
        device_name = allCaptureDevNameMap[0].name;
1039
 
    else
1040
 
    {
1041
 
        ALuint i;
1042
 
 
1043
 
        for(i = 0;i < numCaptureDevNames;i++)
1044
 
        {
1045
 
            if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0)
1046
 
            {
1047
 
                pulse_name = allCaptureDevNameMap[i].device_name;
1048
 
                break;
1049
 
            }
1050
 
        }
1051
 
        if(i == numCaptureDevNames)
1052
 
            return ALC_FALSE;
1053
 
    }
1054
 
 
1055
 
    if(pulse_open(device, device_name) == ALC_FALSE)
1056
 
        return ALC_FALSE;
1057
 
 
1058
 
    data = device->ExtraData;
1059
 
    ppa_threaded_mainloop_lock(data->loop);
1060
 
 
1061
 
    data->samples = device->UpdateSize * device->NumUpdates;
1062
 
    data->frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType);
1063
 
    if(data->samples < 100 * device->Frequency / 1000)
1064
 
        data->samples = 100 * device->Frequency / 1000;
1065
 
 
1066
 
    if(!(data->ring = CreateRingBuffer(data->frame_size, data->samples)))
1067
 
    {
1068
 
        ppa_threaded_mainloop_unlock(data->loop);
1069
 
        goto fail;
1070
 
    }
1071
 
 
1072
 
    data->attr.minreq = -1;
1073
 
    data->attr.prebuf = -1;
1074
 
    data->attr.maxlength = data->samples * data->frame_size;
1075
 
    data->attr.tlength = -1;
1076
 
    data->attr.fragsize = min(data->samples, 50 * device->Frequency / 1000) *
1077
 
                          data->frame_size;
1078
 
 
1079
 
    data->spec.rate = device->Frequency;
1080
 
    data->spec.channels = ChannelsFromDevFmt(device->FmtChans);
1081
 
 
1082
 
    switch(device->FmtType)
1083
 
    {
1084
 
        case DevFmtUByte:
1085
 
            data->spec.format = PA_SAMPLE_U8;
1086
 
            break;
1087
 
        case DevFmtShort:
1088
 
            data->spec.format = PA_SAMPLE_S16NE;
1089
 
            break;
1090
 
        case DevFmtFloat:
1091
 
            data->spec.format = PA_SAMPLE_FLOAT32NE;
1092
 
            break;
1093
 
        case DevFmtByte:
1094
 
        case DevFmtUShort:
1095
 
            AL_PRINT("Capture format type %#x capture not supported on PulseAudio\n", device->FmtType);
1096
 
            ppa_threaded_mainloop_unlock(data->loop);
1097
 
            goto fail;
1098
 
    }
1099
 
 
1100
 
    if(ppa_sample_spec_valid(&data->spec) == 0)
1101
 
    {
1102
 
        AL_PRINT("Invalid sample format\n");
1103
 
        ppa_threaded_mainloop_unlock(data->loop);
1104
 
        goto fail;
1105
 
    }
1106
 
 
1107
 
    if(!ppa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX))
1108
 
    {
1109
 
        AL_PRINT("Couldn't build map for channel count (%d)!\n", data->spec.channels);
1110
 
        ppa_threaded_mainloop_unlock(data->loop);
1111
 
        goto fail;
1112
 
    }
1113
 
 
1114
 
    data->stream = ppa_stream_new(data->context, "Capture Stream", &data->spec, &chanmap);
1115
 
    if(!data->stream)
1116
 
    {
1117
 
        AL_PRINT("pa_stream_new() failed: %s\n",
1118
 
                 ppa_strerror(ppa_context_errno(data->context)));
1119
 
 
1120
 
        ppa_threaded_mainloop_unlock(data->loop);
1121
 
        goto fail;
1122
 
    }
1123
 
 
1124
 
    ppa_stream_set_state_callback(data->stream, stream_state_callback, data->loop);
1125
 
 
1126
 
    flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY;
1127
 
    if(ppa_stream_connect_record(data->stream, pulse_name, &data->attr, flags) < 0)
1128
 
    {
1129
 
        AL_PRINT("Stream did not connect: %s\n",
1130
 
                 ppa_strerror(ppa_context_errno(data->context)));
1131
 
 
1132
 
        ppa_stream_unref(data->stream);
1133
 
        data->stream = NULL;
1134
 
 
1135
 
        ppa_threaded_mainloop_unlock(data->loop);
1136
 
        goto fail;
1137
 
    }
1138
 
 
1139
 
    while((state=ppa_stream_get_state(data->stream)) != PA_STREAM_READY)
1140
 
    {
1141
 
        if(!PA_STREAM_IS_GOOD(state))
1142
 
        {
1143
 
            AL_PRINT("Stream did not get ready: %s\n",
1144
 
                     ppa_strerror(ppa_context_errno(data->context)));
1145
 
 
1146
 
            ppa_stream_unref(data->stream);
1147
 
            data->stream = NULL;
1148
 
 
1149
 
            ppa_threaded_mainloop_unlock(data->loop);
1150
 
            goto fail;
1151
 
        }
1152
 
 
1153
 
        ppa_threaded_mainloop_wait(data->loop);
1154
 
    }
1155
 
    ppa_stream_set_state_callback(data->stream, stream_state_callback2, device);
1156
 
 
1157
 
    ppa_threaded_mainloop_unlock(data->loop);
1158
 
    return ALC_TRUE;
1159
 
 
1160
 
fail:
1161
 
    pulse_close(device);
1162
 
    return ALC_FALSE;
1163
 
} //}}}
1164
 
 
1165
 
static void pulse_close_capture(ALCdevice *device) //{{{
1166
 
{
1167
 
    pulse_close(device);
1168
 
} //}}}
1169
 
 
1170
 
static void pulse_start_capture(ALCdevice *device) //{{{
1171
 
{
1172
 
    pulse_data *data = device->ExtraData;
1173
 
    pa_operation *o;
1174
 
 
1175
 
    ppa_threaded_mainloop_lock(data->loop);
1176
 
    o = ppa_stream_cork(data->stream, 0, stream_success_callback, device);
1177
 
    while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
1178
 
        ppa_threaded_mainloop_wait(data->loop);
1179
 
    ppa_operation_unref(o);
1180
 
    ppa_threaded_mainloop_unlock(data->loop);
1181
 
} //}}}
1182
 
 
1183
 
static void pulse_stop_capture(ALCdevice *device) //{{{
1184
 
{
1185
 
    pulse_data *data = device->ExtraData;
1186
 
    pa_operation *o;
1187
 
 
1188
 
    ppa_threaded_mainloop_lock(data->loop);
1189
 
    o = ppa_stream_cork(data->stream, 1, stream_success_callback, device);
1190
 
    while(ppa_operation_get_state(o) == PA_OPERATION_RUNNING)
1191
 
        ppa_threaded_mainloop_wait(data->loop);
1192
 
    ppa_operation_unref(o);
1193
 
    ppa_threaded_mainloop_unlock(data->loop);
1194
 
} //}}}
1195
 
 
1196
 
static ALCuint pulse_available_samples(ALCdevice *device) //{{{
1197
 
{
1198
 
    pulse_data *data = device->ExtraData;
1199
 
    size_t samples;
1200
 
 
1201
 
    ppa_threaded_mainloop_lock(data->loop);
1202
 
    /* Capture is done in fragment-sized chunks, so we loop until we get all
1203
 
     * that's available */
1204
 
    samples = (device->Connected ? ppa_stream_readable_size(data->stream) : 0);
1205
 
    while(samples > 0)
1206
 
    {
1207
 
        const void *buf;
1208
 
        size_t length;
1209
 
 
1210
 
        if(ppa_stream_peek(data->stream, &buf, &length) < 0)
1211
 
        {
1212
 
            AL_PRINT("pa_stream_peek() failed: %s\n",
1213
 
                     ppa_strerror(ppa_context_errno(data->context)));
1214
 
            break;
1215
 
        }
1216
 
 
1217
 
        WriteRingBuffer(data->ring, buf, length/data->frame_size);
1218
 
        samples -= length;
1219
 
 
1220
 
        ppa_stream_drop(data->stream);
1221
 
    }
1222
 
    ppa_threaded_mainloop_unlock(data->loop);
1223
 
 
1224
 
    return RingBufferSize(data->ring);
1225
 
} //}}}
1226
 
 
1227
 
static void pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) //{{{
1228
 
{
1229
 
    pulse_data *data = device->ExtraData;
1230
 
 
1231
 
    if(pulse_available_samples(device) >= samples)
1232
 
        ReadRingBuffer(data->ring, buffer, samples);
1233
 
    else
1234
 
        alcSetError(device, ALC_INVALID_VALUE);
1235
 
} //}}}
1236
 
 
1237
 
 
1238
 
BackendFuncs pulse_funcs = { //{{{
1239
 
    pulse_open_playback,
1240
 
    pulse_close_playback,
1241
 
    pulse_reset_playback,
1242
 
    pulse_stop_playback,
1243
 
    pulse_open_capture,
1244
 
    pulse_close_capture,
1245
 
    pulse_start_capture,
1246
 
    pulse_stop_capture,
1247
 
    pulse_capture_samples,
1248
 
    pulse_available_samples
1249
 
}; //}}}
1250
 
 
1251
 
void alc_pulse_init(BackendFuncs *func_list) //{{{
1252
 
{
1253
 
    *func_list = pulse_funcs;
1254
 
 
1255
 
    pulse_ctx_flags = 0;
1256
 
    if(!GetConfigValueBool("pulse", "spawn-server", 0))
1257
 
        pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN;
1258
 
} //}}}
1259
 
 
1260
 
void alc_pulse_deinit(void) //{{{
1261
 
{
1262
 
    ALuint i;
1263
 
 
1264
 
    for(i = 0;i < numDevNames;++i)
1265
 
    {
1266
 
        free(allDevNameMap[i].name);
1267
 
        free(allDevNameMap[i].device_name);
1268
 
    }
1269
 
    free(allDevNameMap);
1270
 
    allDevNameMap = NULL;
1271
 
    numDevNames = 0;
1272
 
 
1273
 
    for(i = 0;i < numCaptureDevNames;++i)
1274
 
    {
1275
 
        free(allCaptureDevNameMap[i].name);
1276
 
        free(allCaptureDevNameMap[i].device_name);
1277
 
    }
1278
 
    free(allCaptureDevNameMap);
1279
 
    allCaptureDevNameMap = NULL;
1280
 
    numCaptureDevNames = 0;
1281
 
 
1282
 
    if(pa_handle)
1283
 
    {
1284
 
#ifdef _WIN32
1285
 
        FreeLibrary(pa_handle);
1286
 
#elif defined (HAVE_DLFCN_H)
1287
 
        dlclose(pa_handle);
1288
 
#endif
1289
 
        pa_handle = NULL;
1290
 
    }
1291
 
} //}}}
1292
 
 
1293
 
void alc_pulse_probe(int type) //{{{
1294
 
{
1295
 
    if(!pulse_load()) return;
1296
 
 
1297
 
    if(type == DEVICE_PROBE)
1298
 
    {
1299
 
        pa_threaded_mainloop *loop;
1300
 
 
1301
 
        if((loop=ppa_threaded_mainloop_new()) &&
1302
 
           ppa_threaded_mainloop_start(loop) >= 0)
1303
 
        {
1304
 
            pa_context *context;
1305
 
 
1306
 
            ppa_threaded_mainloop_lock(loop);
1307
 
            context = connect_context(loop);
1308
 
            if(context)
1309
 
            {
1310
 
                AppendDeviceList(pulse_device);
1311
 
 
1312
 
                ppa_context_disconnect(context);
1313
 
                ppa_context_unref(context);
1314
 
            }
1315
 
            ppa_threaded_mainloop_unlock(loop);
1316
 
            ppa_threaded_mainloop_stop(loop);
1317
 
        }
1318
 
        if(loop)
1319
 
            ppa_threaded_mainloop_free(loop);
1320
 
    }
1321
 
    else if(type == ALL_DEVICE_PROBE)
1322
 
    {
1323
 
        ALuint i;
1324
 
 
1325
 
        for(i = 0;i < numDevNames;++i)
1326
 
        {
1327
 
            free(allDevNameMap[i].name);
1328
 
            free(allDevNameMap[i].device_name);
1329
 
        }
1330
 
        free(allDevNameMap);
1331
 
        allDevNameMap = NULL;
1332
 
        numDevNames = 0;
1333
 
 
1334
 
        probe_devices(AL_FALSE);
1335
 
 
1336
 
        for(i = 0;i < numDevNames;i++)
1337
 
            AppendAllDeviceList(allDevNameMap[i].name);
1338
 
    }
1339
 
    else if(type == CAPTURE_DEVICE_PROBE)
1340
 
    {
1341
 
        ALuint i;
1342
 
 
1343
 
        for(i = 0;i < numCaptureDevNames;++i)
1344
 
        {
1345
 
            free(allCaptureDevNameMap[i].name);
1346
 
            free(allCaptureDevNameMap[i].device_name);
1347
 
        }
1348
 
        free(allCaptureDevNameMap);
1349
 
        allCaptureDevNameMap = NULL;
1350
 
        numCaptureDevNames = 0;
1351
 
 
1352
 
        probe_devices(AL_TRUE);
1353
 
 
1354
 
        for(i = 0;i < numCaptureDevNames;i++)
1355
 
            AppendCaptureDeviceList(allCaptureDevNameMap[i].name);
1356
 
    }
1357
 
} //}}}
1358
 
//}}}