~diwic/ubuntu/lucid/pulseaudio/bugfixes

« back to all changes in this revision

Viewing changes to src/modules/module-solaris.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2009-05-05 14:18:20 UTC
  • mfrom: (1.2.4 upstream) (1.1.8 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090505141820-rrr2mtdd1jkllvr8
Tags: 1:0.9.15-1ubuntu1
* Merge from unreleased Debian pulseaudio git, remaining changes:
  - epoch (my stupid fault :S)
  - Don't build against, and create jack package. Jack is not in main
  - use linear resampler to work better with lack of PREEMPT in jaunty's
    -generic kernel config, also change buffer size
  - Add alsa configuration files to route alsa applications via pulseaudio
  - Move libasound2-plugins from Recommends to Depends
  - Add pm-utils sleep hook to suspend (and resume) users' pulseaudio
    daemons
  - patch to fix source/sink and suspend-on-idle race
  - Make initscript more informative in the default case of per-user
    sessions
  - create /var/run/pulse, and make restart more robust
  - add status check for system wide pulseaudio instance
  - LSB {Required-*,Should-*} should specify hal instead of dbus,
    since hal is required (and already requires dbus)
  - indicate that the system pulseaudio instance is being started from the init
    script
  - Install more upstream man pages
  - Link to pacat for parec man page
  - check whether pulseaudio is running before preloading the padsp library
  - Add DEB_OPT_FLAG = -O3 as per recommendation from
    pulseaudio-discuss/2007-December/001017.html
  - cache /usr/share/sounds/ubuntu/stereo/ wav files on pulseaudio load
  - disable glitch free (use tsched=0)
  - Generate a PO template on build
  - add special case to disable pulseaudio loading if accessibility/speech
    is being used
  - the sd wrapper script should not load pulseaudio if pulseaudio is being
    used as a system service
  - add a pulseaudio apport hook
  - fix some typos in README.Debian
  - demote paprefs to suggests
  - drop padevchooser(Recommends) and pavucontrol (Suggests)
  - drop libasyncns-dev build dependency, its in universe
* add libudev-dev as a build-dependency

Show diffs side-by-side

added added

removed removed

Lines of Context:
3
3
 
4
4
  Copyright 2006 Lennart Poettering
5
5
  Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
 
6
  Copyright 2009 Finn Thain
6
7
 
7
8
  PulseAudio is free software; you can redistribute it and/or modify
8
9
  it under the terms of the GNU Lesser General Public License as published
9
 
  by the Free Software Foundation; either version 2 of the License,
 
10
  by the Free Software Foundation; either version 2.1 of the License,
10
11
  or (at your option) any later version.
11
12
 
12
13
  PulseAudio is distributed in the hope that it will be useful, but
44
45
#include <pulse/mainloop-signal.h>
45
46
#include <pulse/xmalloc.h>
46
47
#include <pulse/timeval.h>
 
48
#include <pulse/util.h>
47
49
 
48
50
#include <pulsecore/iochannel.h>
49
51
#include <pulsecore/sink.h>
57
59
#include <pulsecore/thread-mq.h>
58
60
#include <pulsecore/rtpoll.h>
59
61
#include <pulsecore/thread.h>
 
62
#include <pulsecore/rtclock.h>
60
63
 
61
64
#include "module-solaris-symdef.h"
62
65
 
63
 
PA_MODULE_AUTHOR("Pierre Ossman")
64
 
PA_MODULE_DESCRIPTION("Solaris Sink/Source")
65
 
PA_MODULE_VERSION(PACKAGE_VERSION)
 
66
PA_MODULE_AUTHOR("Pierre Ossman");
 
67
PA_MODULE_DESCRIPTION("Solaris Sink/Source");
 
68
PA_MODULE_VERSION(PACKAGE_VERSION);
66
69
PA_MODULE_USAGE(
67
70
    "sink_name=<name for the sink> "
68
71
    "source_name=<name for the source> "
69
 
    "device=<OSS device> record=<enable source?> "
 
72
    "device=<audio device file name> "
 
73
    "record=<enable source?> "
70
74
    "playback=<enable sink?> "
71
75
    "format=<sample format> "
72
76
    "channels=<number of channels> "
73
77
    "rate=<sample rate> "
74
 
    "buffer_size=<record buffer size> "
75
 
    "channel_map=<channel map>")
 
78
    "buffer_length=<milliseconds> "
 
79
    "channel_map=<channel map>");
 
80
PA_MODULE_LOAD_ONCE(FALSE);
76
81
 
77
82
struct userdata {
78
83
    pa_core *core;
87
92
 
88
93
    pa_memchunk memchunk;
89
94
 
90
 
    unsigned int page_size;
91
 
 
92
95
    uint32_t frame_size;
93
 
    uint32_t buffer_size;
94
 
    unsigned int written_bytes, read_bytes;
 
96
    int32_t buffer_size;
 
97
    uint64_t written_bytes, read_bytes;
95
98
 
 
99
    char *device_name;
 
100
    int mode;
96
101
    int fd;
97
102
    pa_rtpoll_item *rtpoll_item;
98
103
    pa_module *module;
 
104
 
 
105
    pa_bool_t sink_suspended, source_suspended;
 
106
 
 
107
    uint32_t play_samples_msw, record_samples_msw;
 
108
    uint32_t prev_playback_samples, prev_record_samples;
 
109
 
 
110
    int32_t minimum_request;
99
111
};
100
112
 
101
113
static const char* const valid_modargs[] = {
104
116
    "device",
105
117
    "record",
106
118
    "playback",
107
 
    "buffer_size",
 
119
    "buffer_length",
108
120
    "format",
109
121
    "rate",
110
122
    "channels",
112
124
    NULL
113
125
};
114
126
 
115
 
#define DEFAULT_SINK_NAME "solaris_output"
116
 
#define DEFAULT_SOURCE_NAME "solaris_input"
117
127
#define DEFAULT_DEVICE "/dev/audio"
118
128
 
 
129
#define MAX_RENDER_HZ   (300)
 
130
/* This render rate limit imposes a minimum latency, but without it we waste too much CPU time. */
 
131
 
 
132
static uint64_t get_playback_buffered_bytes(struct userdata *u) {
 
133
    audio_info_t info;
 
134
    uint64_t played_bytes;
 
135
    int err;
 
136
 
 
137
    pa_assert(u->sink);
 
138
 
 
139
    err = ioctl(u->fd, AUDIO_GETINFO, &info);
 
140
    pa_assert(err >= 0);
 
141
 
 
142
    /* Handle wrap-around of the device's sample counter, which is a uint_32. */
 
143
    if (u->prev_playback_samples > info.play.samples) {
 
144
        /* Unfortunately info.play.samples can sometimes go backwards, even before it wraps! */
 
145
        if (u->prev_playback_samples + info.play.samples < 240000) {
 
146
            ++u->play_samples_msw;
 
147
        } else {
 
148
            pa_log_debug("play.samples went backwards %d bytes", u->prev_playback_samples - info.play.samples);
 
149
        }
 
150
    }
 
151
    u->prev_playback_samples = info.play.samples;
 
152
    played_bytes = (((uint64_t)u->play_samples_msw << 32) + info.play.samples) * u->frame_size;
 
153
 
 
154
    return u->written_bytes - played_bytes;
 
155
}
 
156
 
 
157
static pa_usec_t sink_get_latency(struct userdata *u, pa_sample_spec *ss) {
 
158
    pa_usec_t r = 0;
 
159
 
 
160
    pa_assert(u);
 
161
    pa_assert(ss);
 
162
 
 
163
    if (u->fd >= 0) {
 
164
        r = pa_bytes_to_usec(get_playback_buffered_bytes(u), ss);
 
165
        if (u->memchunk.memblock)
 
166
            r += pa_bytes_to_usec(u->memchunk.length, ss);
 
167
    }
 
168
    return r;
 
169
}
 
170
 
 
171
static uint64_t get_recorded_bytes(struct userdata *u) {
 
172
    audio_info_t info;
 
173
    uint64_t result;
 
174
    int err;
 
175
 
 
176
    pa_assert(u->source);
 
177
 
 
178
    err = ioctl(u->fd, AUDIO_GETINFO, &info);
 
179
    pa_assert(err >= 0);
 
180
 
 
181
    if (u->prev_record_samples > info.record.samples)
 
182
        ++u->record_samples_msw;
 
183
    u->prev_record_samples = info.record.samples;
 
184
    result = (((uint64_t)u->record_samples_msw << 32) + info.record.samples) * u->frame_size;
 
185
 
 
186
    return result;
 
187
}
 
188
 
 
189
static pa_usec_t source_get_latency(struct userdata *u, pa_sample_spec *ss) {
 
190
    pa_usec_t r = 0;
 
191
    audio_info_t info;
 
192
 
 
193
    pa_assert(u);
 
194
    pa_assert(ss);
 
195
 
 
196
    if (u->fd) {
 
197
        int err = ioctl(u->fd, AUDIO_GETINFO, &info);
 
198
        pa_assert(err >= 0);
 
199
 
 
200
        r = pa_bytes_to_usec(get_recorded_bytes(u), ss) - pa_bytes_to_usec(u->read_bytes, ss);
 
201
    }
 
202
    return r;
 
203
}
 
204
 
 
205
static void build_pollfd(struct userdata *u) {
 
206
    struct pollfd *pollfd;
 
207
 
 
208
    pa_assert(u);
 
209
    pa_assert(!u->rtpoll_item);
 
210
    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
 
211
 
 
212
    pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
 
213
    pollfd->fd = u->fd;
 
214
    pollfd->events = 0;
 
215
    pollfd->revents = 0;
 
216
}
 
217
 
 
218
static int set_buffer(int fd, int buffer_size) {
 
219
    audio_info_t info;
 
220
 
 
221
    pa_assert(fd >= 0);
 
222
 
 
223
    AUDIO_INITINFO(&info);
 
224
    info.play.buffer_size = buffer_size;
 
225
    info.record.buffer_size = buffer_size;
 
226
 
 
227
    if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
 
228
        if (errno == EINVAL)
 
229
            pa_log("AUDIO_SETINFO: Unsupported buffer size.");
 
230
        else
 
231
            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
 
232
        return -1;
 
233
    }
 
234
 
 
235
    return 0;
 
236
}
 
237
 
 
238
static int auto_format(int fd, int mode, pa_sample_spec *ss) {
 
239
    audio_info_t info;
 
240
 
 
241
    pa_assert(fd >= 0);
 
242
    pa_assert(ss);
 
243
 
 
244
    AUDIO_INITINFO(&info);
 
245
 
 
246
    if (mode != O_RDONLY) {
 
247
        info.play.sample_rate = ss->rate;
 
248
        info.play.channels = ss->channels;
 
249
        switch (ss->format) {
 
250
        case PA_SAMPLE_U8:
 
251
            info.play.precision = 8;
 
252
            info.play.encoding = AUDIO_ENCODING_LINEAR;
 
253
            break;
 
254
        case PA_SAMPLE_ALAW:
 
255
            info.play.precision = 8;
 
256
            info.play.encoding = AUDIO_ENCODING_ALAW;
 
257
            break;
 
258
        case PA_SAMPLE_ULAW:
 
259
            info.play.precision = 8;
 
260
            info.play.encoding = AUDIO_ENCODING_ULAW;
 
261
            break;
 
262
        case PA_SAMPLE_S16NE:
 
263
            info.play.precision = 16;
 
264
            info.play.encoding = AUDIO_ENCODING_LINEAR;
 
265
            break;
 
266
        default:
 
267
            pa_log("AUDIO_SETINFO: Unsupported sample format.");
 
268
            return -1;
 
269
        }
 
270
    }
 
271
 
 
272
    if (mode != O_WRONLY) {
 
273
        info.record.sample_rate = ss->rate;
 
274
        info.record.channels = ss->channels;
 
275
        switch (ss->format) {
 
276
        case PA_SAMPLE_U8:
 
277
            info.record.precision = 8;
 
278
            info.record.encoding = AUDIO_ENCODING_LINEAR;
 
279
            break;
 
280
        case PA_SAMPLE_ALAW:
 
281
            info.record.precision = 8;
 
282
            info.record.encoding = AUDIO_ENCODING_ALAW;
 
283
            break;
 
284
        case PA_SAMPLE_ULAW:
 
285
            info.record.precision = 8;
 
286
            info.record.encoding = AUDIO_ENCODING_ULAW;
 
287
            break;
 
288
        case PA_SAMPLE_S16NE:
 
289
            info.record.precision = 16;
 
290
            info.record.encoding = AUDIO_ENCODING_LINEAR;
 
291
            break;
 
292
        default:
 
293
             pa_log("AUDIO_SETINFO: Unsupported sample format.");
 
294
             return -1;
 
295
        }
 
296
    }
 
297
 
 
298
    if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
 
299
        if (errno == EINVAL)
 
300
            pa_log("AUDIO_SETINFO: Failed to set sample format.");
 
301
        else
 
302
            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
 
303
        return -1;
 
304
    }
 
305
 
 
306
    return 0;
 
307
}
 
308
 
 
309
static int open_audio_device(struct userdata *u, pa_sample_spec *ss) {
 
310
    pa_assert(u);
 
311
    pa_assert(ss);
 
312
 
 
313
    if ((u->fd = open(u->device_name, u->mode | O_NONBLOCK)) < 0) {
 
314
        pa_log_warn("open %s failed (%s)", u->device_name, pa_cstrerror(errno));
 
315
        return -1;
 
316
    }
 
317
 
 
318
    pa_log_info("device opened in %s mode.", u->mode == O_WRONLY ? "O_WRONLY" : (u->mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
 
319
 
 
320
    if (auto_format(u->fd, u->mode, ss) < 0)
 
321
        return -1;
 
322
 
 
323
    if (set_buffer(u->fd, u->buffer_size) < 0)
 
324
        return -1;
 
325
 
 
326
    u->written_bytes = u->read_bytes = 0;
 
327
    u->play_samples_msw = u->record_samples_msw = 0;
 
328
    u->prev_playback_samples = u->prev_record_samples = 0;
 
329
 
 
330
    return u->fd;
 
331
}
 
332
 
 
333
static int suspend(struct userdata *u) {
 
334
    pa_assert(u);
 
335
    pa_assert(u->fd >= 0);
 
336
 
 
337
    pa_log_info("Suspending...");
 
338
 
 
339
    ioctl(u->fd, AUDIO_DRAIN, NULL);
 
340
    pa_close(u->fd);
 
341
    u->fd = -1;
 
342
 
 
343
    if (u->rtpoll_item) {
 
344
        pa_rtpoll_item_free(u->rtpoll_item);
 
345
        u->rtpoll_item = NULL;
 
346
    }
 
347
 
 
348
    pa_log_info("Device suspended.");
 
349
 
 
350
    return 0;
 
351
}
 
352
 
 
353
static int unsuspend(struct userdata *u) {
 
354
    pa_assert(u);
 
355
    pa_assert(u->fd < 0);
 
356
 
 
357
    pa_log_info("Resuming...");
 
358
 
 
359
    if (open_audio_device(u, u->sink ? &u->sink->sample_spec : &u->source->sample_spec) < 0)
 
360
        return -1;
 
361
 
 
362
    build_pollfd(u);
 
363
 
 
364
    pa_log_info("Device resumed.");
 
365
 
 
366
    return 0;
 
367
}
 
368
 
119
369
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
120
370
    struct userdata *u = PA_SINK(o)->userdata;
121
 
    int err;
122
 
    audio_info_t info;
123
371
 
124
372
    switch (code) {
125
 
    case PA_SINK_MESSAGE_GET_LATENCY: {
126
 
        pa_usec_t r = 0;
127
 
 
128
 
        if (u->fd >= 0) {
129
 
 
130
 
            err = ioctl(u->fd, AUDIO_GETINFO, &info);
131
 
            pa_assert(err >= 0);
132
 
 
133
 
            r += pa_bytes_to_usec(u->written_bytes, &PA_SINK(o)->sample_spec);
134
 
            r -= pa_bytes_to_usec(info.play.samples * u->frame_size, &PA_SINK(o)->sample_spec);
135
 
 
136
 
            if (u->memchunk.memblock)
137
 
                r += pa_bytes_to_usec(u->memchunk.length, &PA_SINK(o)->sample_spec);
138
 
        }
139
 
 
140
 
        *((pa_usec_t*) data) = r;
141
 
 
142
 
        return 0;
143
 
    }
144
 
 
145
 
    case PA_SINK_MESSAGE_SET_VOLUME:
146
 
        if (u->fd >= 0) {
147
 
            AUDIO_INITINFO(&info);
148
 
 
149
 
            info.play.gain = pa_cvolume_avg((pa_cvolume*)data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
150
 
            assert(info.play.gain <= AUDIO_MAX_GAIN);
151
 
 
152
 
            if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
153
 
                if (errno == EINVAL)
154
 
                    pa_log("AUDIO_SETINFO: Unsupported volume.");
155
 
                else
156
 
                    pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
157
 
            } else {
158
 
                return 0;
 
373
 
 
374
        case PA_SINK_MESSAGE_GET_LATENCY:
 
375
            *((pa_usec_t*) data) = sink_get_latency(u, &PA_SINK(o)->sample_spec);
 
376
            return 0;
 
377
 
 
378
        case PA_SINK_MESSAGE_SET_STATE:
 
379
 
 
380
            switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
 
381
 
 
382
                case PA_SINK_SUSPENDED:
 
383
 
 
384
                    pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
 
385
 
 
386
                    if (!u->source || u->source_suspended) {
 
387
                        if (suspend(u) < 0)
 
388
                            return -1;
 
389
                    }
 
390
                    u->sink_suspended = TRUE;
 
391
                    break;
 
392
 
 
393
                case PA_SINK_IDLE:
 
394
                case PA_SINK_RUNNING:
 
395
 
 
396
                    if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
 
397
                        if (!u->source || u->source_suspended) {
 
398
                            if (unsuspend(u) < 0)
 
399
                                return -1;
 
400
                            u->sink->get_volume(u->sink);
 
401
                            u->sink->get_mute(u->sink);
 
402
                        }
 
403
                        u->sink_suspended = FALSE;
 
404
                    }
 
405
                    break;
 
406
 
 
407
                case PA_SINK_INVALID_STATE:
 
408
                case PA_SINK_UNLINKED:
 
409
                case PA_SINK_INIT:
 
410
                    ;
159
411
            }
160
 
        }
161
 
        break;
162
 
 
163
 
    case PA_SINK_MESSAGE_GET_VOLUME:
164
 
        if (u->fd >= 0) {
165
 
            err = ioctl(u->fd, AUDIO_GETINFO, &info);
166
 
            assert(err >= 0);
167
 
 
168
 
            pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels,
169
 
                info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
170
 
 
171
 
            return 0;
172
 
        }
173
 
        break;
174
 
 
175
 
    case PA_SINK_MESSAGE_SET_MUTE:
176
 
        if (u->fd >= 0) {
177
 
            AUDIO_INITINFO(&info);
178
 
 
179
 
            info.output_muted = !!PA_PTR_TO_UINT(data);
180
 
 
181
 
            if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
182
 
                pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
183
 
            else
184
 
                return 0;
185
 
        }
186
 
        break;
187
 
 
188
 
    case PA_SINK_MESSAGE_GET_MUTE:
189
 
        if (u->fd >= 0) {
190
 
            err = ioctl(u->fd, AUDIO_GETINFO, &info);
191
 
            pa_assert(err >= 0);
192
 
 
193
 
            *(int*)data = !!info.output_muted;
194
 
 
195
 
            return 0;
196
 
        }
197
 
        break;
 
412
 
 
413
            break;
198
414
    }
199
415
 
200
416
    return pa_sink_process_msg(o, code, data, offset, chunk);
202
418
 
203
419
static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
204
420
    struct userdata *u = PA_SOURCE(o)->userdata;
205
 
    int err;
206
 
    audio_info_t info;
207
421
 
208
422
    switch (code) {
209
 
        case PA_SOURCE_MESSAGE_GET_LATENCY: {
210
 
            pa_usec_t r = 0;
211
 
 
212
 
            if (u->fd) {
213
 
                err = ioctl(u->fd, AUDIO_GETINFO, &info);
214
 
                pa_assert(err >= 0);
215
 
 
216
 
                r += pa_bytes_to_usec(info.record.samples * u->frame_size, &PA_SOURCE(o)->sample_spec);
217
 
                r -= pa_bytes_to_usec(u->read_bytes, &PA_SOURCE(o)->sample_spec);
218
 
            }
219
 
 
220
 
            *((pa_usec_t*) data) = r;
221
 
 
 
423
 
 
424
        case PA_SOURCE_MESSAGE_GET_LATENCY:
 
425
            *((pa_usec_t*) data) = source_get_latency(u, &PA_SOURCE(o)->sample_spec);
222
426
            return 0;
223
 
        }
224
 
 
225
 
        case PA_SOURCE_MESSAGE_SET_VOLUME:
226
 
            if (u->fd >= 0) {
227
 
                AUDIO_INITINFO(&info);
228
 
 
229
 
                info.record.gain = pa_cvolume_avg((pa_cvolume*) data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
230
 
                assert(info.record.gain <= AUDIO_MAX_GAIN);
231
 
 
232
 
                if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
233
 
                    if (errno == EINVAL)
234
 
                        pa_log("AUDIO_SETINFO: Unsupported volume.");
235
 
                    else
236
 
                        pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
237
 
                } else {
238
 
                    return 0;
239
 
                }
240
 
            }
241
 
            break;
242
 
 
243
 
        case PA_SOURCE_MESSAGE_GET_VOLUME:
244
 
            if (u->fd >= 0) {
245
 
                err = ioctl(u->fd, AUDIO_GETINFO, &info);
246
 
                pa_assert(err >= 0);
247
 
 
248
 
                pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels,
249
 
                    info.record.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
250
 
 
251
 
                return 0;
252
 
            }
253
 
            break;
 
427
 
 
428
        case PA_SOURCE_MESSAGE_SET_STATE:
 
429
 
 
430
            switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
 
431
 
 
432
                case PA_SOURCE_SUSPENDED:
 
433
 
 
434
                    pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
 
435
 
 
436
                    if (!u->sink || u->sink_suspended) {
 
437
                        if (suspend(u) < 0)
 
438
                            return -1;
 
439
                    }
 
440
                    u->source_suspended = TRUE;
 
441
                    break;
 
442
 
 
443
                case PA_SOURCE_IDLE:
 
444
                case PA_SOURCE_RUNNING:
 
445
 
 
446
                    if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
 
447
                        if (!u->sink || u->sink_suspended) {
 
448
                            if (unsuspend(u) < 0)
 
449
                                return -1;
 
450
                            u->source->get_volume(u->source);
 
451
                        }
 
452
                        u->source_suspended = FALSE;
 
453
                    }
 
454
                    break;
 
455
 
 
456
                case PA_SOURCE_UNLINKED:
 
457
                case PA_SOURCE_INIT:
 
458
                case PA_SOURCE_INVALID_STATE:
 
459
                    ;
 
460
 
 
461
            }
 
462
            break;
 
463
 
254
464
    }
255
465
 
256
466
    return pa_source_process_msg(o, code, data, offset, chunk);
257
467
}
258
468
 
259
 
static void clear_underflow(struct userdata *u)
260
 
{
261
 
    audio_info_t info;
262
 
 
263
 
    AUDIO_INITINFO(&info);
264
 
 
265
 
    info.play.error = 0;
266
 
 
267
 
    if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
268
 
        pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
269
 
}
270
 
 
271
 
static void clear_overflow(struct userdata *u)
272
 
{
273
 
    audio_info_t info;
274
 
 
275
 
    AUDIO_INITINFO(&info);
276
 
 
277
 
    info.record.error = 0;
278
 
 
279
 
    if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
280
 
        pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
 
469
static void sink_set_volume(pa_sink *s) {
 
470
    struct userdata *u;
 
471
    audio_info_t info;
 
472
 
 
473
    pa_assert_se(u = s->userdata);
 
474
 
 
475
    if (u->fd >= 0) {
 
476
        AUDIO_INITINFO(&info);
 
477
 
 
478
        info.play.gain = pa_cvolume_max(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
 
479
        assert(info.play.gain <= AUDIO_MAX_GAIN);
 
480
 
 
481
        if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
 
482
            if (errno == EINVAL)
 
483
                pa_log("AUDIO_SETINFO: Unsupported volume.");
 
484
            else
 
485
                pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
 
486
        }
 
487
    }
 
488
}
 
489
 
 
490
static void sink_get_volume(pa_sink *s) {
 
491
    struct userdata *u;
 
492
    audio_info_t info;
 
493
 
 
494
    pa_assert_se(u = s->userdata);
 
495
 
 
496
    if (u->fd >= 0) {
 
497
        if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
 
498
            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
 
499
        else
 
500
            pa_cvolume_set(&s->virtual_volume, s->sample_spec.channels,
 
501
                info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
 
502
    }
 
503
}
 
504
 
 
505
static void source_set_volume(pa_source *s) {
 
506
    struct userdata *u;
 
507
    audio_info_t info;
 
508
 
 
509
    pa_assert_se(u = s->userdata);
 
510
 
 
511
    if (u->fd >= 0) {
 
512
        AUDIO_INITINFO(&info);
 
513
 
 
514
        info.play.gain = pa_cvolume_max(&s->virtual_volume) * AUDIO_MAX_GAIN / PA_VOLUME_NORM;
 
515
        assert(info.play.gain <= AUDIO_MAX_GAIN);
 
516
 
 
517
        if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) {
 
518
            if (errno == EINVAL)
 
519
                pa_log("AUDIO_SETINFO: Unsupported volume.");
 
520
            else
 
521
                pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
 
522
        }
 
523
    }
 
524
}
 
525
 
 
526
static void source_get_volume(pa_source *s) {
 
527
    struct userdata *u;
 
528
    audio_info_t info;
 
529
 
 
530
    pa_assert_se(u = s->userdata);
 
531
 
 
532
    if (u->fd >= 0) {
 
533
        if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
 
534
            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
 
535
        else
 
536
            pa_cvolume_set(&s->virtual_volume, s->sample_spec.channels,
 
537
                info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN);
 
538
    }
 
539
}
 
540
 
 
541
static void sink_set_mute(pa_sink *s) {
 
542
    struct userdata *u = s->userdata;
 
543
    audio_info_t info;
 
544
 
 
545
    pa_assert(u);
 
546
 
 
547
    if (u->fd >= 0) {
 
548
        AUDIO_INITINFO(&info);
 
549
 
 
550
        info.output_muted = !!s->muted;
 
551
 
 
552
        if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
 
553
            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
 
554
    }
 
555
}
 
556
 
 
557
static void sink_get_mute(pa_sink *s) {
 
558
    struct userdata *u = s->userdata;
 
559
    audio_info_t info;
 
560
 
 
561
    pa_assert(u);
 
562
 
 
563
    if (u->fd >= 0) {
 
564
        if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0)
 
565
            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
 
566
        else
 
567
            s->muted = !!info.output_muted;
 
568
    }
 
569
}
 
570
 
 
571
static void process_rewind(struct userdata *u) {
 
572
    size_t rewind_nbytes;
 
573
 
 
574
    pa_assert(u);
 
575
 
 
576
    /* Figure out how much we shall rewind and reset the counter */
 
577
    rewind_nbytes = u->sink->thread_info.rewind_nbytes;
 
578
    u->sink->thread_info.rewind_nbytes = 0;
 
579
 
 
580
    if (rewind_nbytes > 0) {
 
581
        pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes);
 
582
        rewind_nbytes = PA_MIN(u->memchunk.length, rewind_nbytes);
 
583
        u->memchunk.length -= rewind_nbytes;
 
584
        pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes);
 
585
    }
 
586
 
 
587
    pa_sink_process_rewind(u->sink, rewind_nbytes);
281
588
}
282
589
 
283
590
static void thread_func(void *userdata) {
284
591
    struct userdata *u = userdata;
285
592
    unsigned short revents = 0;
286
 
    int ret;
 
593
    int ret, err;
 
594
    audio_info_t info;
287
595
 
288
596
    pa_assert(u);
289
597
 
290
598
    pa_log_debug("Thread starting up");
291
599
 
292
 
    if (u->core->high_priority)
293
 
        pa_make_realtime();
 
600
    if (u->core->realtime_scheduling)
 
601
        pa_make_realtime(u->core->realtime_priority);
294
602
 
295
603
    pa_thread_mq_install(&u->thread_mq);
296
604
    pa_rtpoll_install(u->rtpoll);
298
606
    for (;;) {
299
607
        /* Render some data and write it to the dsp */
300
608
 
301
 
        if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) {
302
 
            audio_info_t info;
303
 
            int err;
304
 
            size_t len;
 
609
        if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
 
610
            pa_usec_t xtime0;
 
611
            uint64_t buffered_bytes;
 
612
 
 
613
            if (u->sink->thread_info.rewind_requested)
 
614
                process_rewind(u);
305
615
 
306
616
            err = ioctl(u->fd, AUDIO_GETINFO, &info);
307
 
            pa_assert(err >= 0);
308
 
 
309
 
            /*
310
 
             * Since we cannot modify the size of the output buffer we fake it
311
 
             * by not filling it more than u->buffer_size.
312
 
             */
313
 
            len = u->buffer_size;
314
 
            len -= u->written_bytes - (info.play.samples * u->frame_size);
315
 
 
316
 
            /* The sample counter can sometimes go backwards :( */
317
 
            if (len > u->buffer_size)
318
 
                len = 0;
 
617
            if (err < 0) {
 
618
                pa_log("AUDIO_GETINFO ioctl failed: %s", pa_cstrerror(errno));
 
619
                goto fail;
 
620
            }
319
621
 
320
622
            if (info.play.error) {
321
 
                pa_log_debug("Solaris buffer underflow!");
322
 
                clear_underflow(u);
 
623
                pa_log_debug("buffer under-run!");
 
624
 
 
625
                AUDIO_INITINFO(&info);
 
626
                info.play.error = 0;
 
627
                if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
 
628
                    pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
323
629
            }
324
630
 
325
 
            len -= len % u->frame_size;
326
 
 
327
 
            while (len) {
 
631
            for (;;) {
328
632
                void *p;
329
 
                ssize_t r;
330
 
 
331
 
                if (!u->memchunk.length)
332
 
                    pa_sink_render(u->sink, len, &u->memchunk);
333
 
 
334
 
                pa_assert(u->memchunk.length);
 
633
                ssize_t w;
 
634
                size_t len;
 
635
 
 
636
                /*
 
637
                 * Since we cannot modify the size of the output buffer we fake it
 
638
                 * by not filling it more than u->buffer_size.
 
639
                 */
 
640
                xtime0 = pa_rtclock_usec();
 
641
                buffered_bytes = get_playback_buffered_bytes(u);
 
642
                if (buffered_bytes >= (uint64_t)u->buffer_size)
 
643
                    break;
 
644
 
 
645
                len = u->buffer_size - buffered_bytes;
 
646
                len -= len % u->frame_size;
 
647
 
 
648
                if (len < (size_t) u->minimum_request)
 
649
                    break;
 
650
 
 
651
                if (u->memchunk.length < len)
 
652
                    pa_sink_render(u->sink, u->sink->thread_info.max_request, &u->memchunk);
335
653
 
336
654
                p = pa_memblock_acquire(u->memchunk.memblock);
337
 
                r = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, NULL);
 
655
                w = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, NULL);
338
656
                pa_memblock_release(u->memchunk.memblock);
339
657
 
340
 
                if (r < 0) {
341
 
                    if (errno == EINTR)
342
 
                        continue;
343
 
                    else if (errno != EAGAIN) {
344
 
                        pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
345
 
                        goto fail;
 
658
                if (w <= 0) {
 
659
                    switch (errno) {
 
660
                        case EINTR:
 
661
                            continue;
 
662
                        case EAGAIN:
 
663
                            /* If the buffer_size is too big, we get EAGAIN. Avoiding that limit by trial and error
 
664
                             * is not ideal, but I don't know how to get the system to tell me what the limit is.
 
665
                             */
 
666
                            u->buffer_size = u->buffer_size * 18 / 25;
 
667
                            u->buffer_size -= u->buffer_size % u->frame_size;
 
668
                            u->buffer_size = PA_MAX(u->buffer_size, 2 * u->minimum_request);
 
669
                            pa_sink_set_max_request_within_thread(u->sink, u->buffer_size);
 
670
                            pa_sink_set_max_rewind_within_thread(u->sink, u->buffer_size);
 
671
                            pa_log("EAGAIN. Buffer size is now %u bytes (%llu buffered)", u->buffer_size, buffered_bytes);
 
672
                            break;
 
673
                        default:
 
674
                            pa_log("Failed to write data to DSP: %s", pa_cstrerror(errno));
 
675
                            goto fail;
346
676
                    }
347
677
                } else {
348
 
                    pa_assert(r % u->frame_size == 0);
349
 
 
350
 
                    u->memchunk.index += r;
351
 
                    u->memchunk.length -= r;
352
 
 
 
678
                    pa_assert(w % u->frame_size == 0);
 
679
 
 
680
                    u->written_bytes += w;
 
681
                    u->memchunk.length -= w;
 
682
 
 
683
                    u->memchunk.index += w;
353
684
                    if (u->memchunk.length <= 0) {
354
685
                        pa_memblock_unref(u->memchunk.memblock);
355
686
                        pa_memchunk_reset(&u->memchunk);
356
687
                    }
357
 
 
358
 
                    len -= r;
359
 
                    u->written_bytes += r;
360
688
                }
361
689
            }
362
 
        }
 
690
 
 
691
            pa_rtpoll_set_timer_absolute(u->rtpoll, xtime0 + pa_bytes_to_usec(buffered_bytes / 2, &u->sink->sample_spec));
 
692
        } else
 
693
            pa_rtpoll_set_timer_disabled(u->rtpoll);
363
694
 
364
695
        /* Try to read some data and pass it on to the source driver */
365
696
 
366
 
        if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state) && ((revents & POLLIN))) {
 
697
        if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state) && (revents & POLLIN)) {
367
698
            pa_memchunk memchunk;
368
 
            int err;
369
 
            size_t l;
370
699
            void *p;
371
700
            ssize_t r;
372
 
            audio_info_t info;
 
701
            size_t len;
373
702
 
374
703
            err = ioctl(u->fd, AUDIO_GETINFO, &info);
375
704
            pa_assert(err >= 0);
376
705
 
377
706
            if (info.record.error) {
378
 
                pa_log_debug("Solaris buffer overflow!");
379
 
                clear_overflow(u);
 
707
                pa_log_debug("buffer overflow!");
 
708
 
 
709
                AUDIO_INITINFO(&info);
 
710
                info.record.error = 0;
 
711
                if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0)
 
712
                    pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
380
713
            }
381
714
 
382
 
            err = ioctl(u->fd, I_NREAD, &l);
 
715
            err = ioctl(u->fd, I_NREAD, &len);
383
716
            pa_assert(err >= 0);
384
717
 
385
 
            if (l > 0) {
386
 
                /* This is to make sure it fits in the memory pool. Also, a page
387
 
                   should be the most efficient transfer size. */
388
 
                if (l > u->page_size)
389
 
                    l = u->page_size;
390
 
 
391
 
                memchunk.memblock = pa_memblock_new(u->core->mempool, l);
 
718
            if (len > 0) {
 
719
                memchunk.memblock = pa_memblock_new(u->core->mempool, len);
392
720
                pa_assert(memchunk.memblock);
393
721
 
394
722
                p = pa_memblock_acquire(memchunk.memblock);
395
 
                r = pa_read(u->fd, p, l, NULL);
 
723
                r = pa_read(u->fd, p, len, NULL);
396
724
                pa_memblock_release(memchunk.memblock);
397
725
 
398
726
                if (r < 0) {
399
727
                    pa_memblock_unref(memchunk.memblock);
400
 
                    if (errno != EAGAIN) {
 
728
                    if (errno == EAGAIN)
 
729
                        break;
 
730
                    else {
401
731
                        pa_log("Failed to read data from DSP: %s", pa_cstrerror(errno));
402
732
                        goto fail;
403
733
                    }
404
734
                } else {
 
735
                    u->read_bytes += r;
 
736
 
405
737
                    memchunk.index = 0;
406
738
                    memchunk.length = r;
407
739
 
408
740
                    pa_source_post(u->source, &memchunk);
409
741
                    pa_memblock_unref(memchunk.memblock);
410
742
 
411
 
                    u->read_bytes += r;
412
 
 
413
743
                    revents &= ~POLLIN;
414
744
                }
415
745
            }
416
746
        }
417
747
 
418
 
        if (u->fd >= 0) {
 
748
        if (u->rtpoll_item) {
419
749
            struct pollfd *pollfd;
420
750
 
 
751
            pa_assert(u->fd >= 0);
 
752
 
421
753
            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
422
 
            pollfd->events =
423
 
                ((u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) ? POLLIN : 0);
 
754
            pollfd->events = (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) ? POLLIN : 0;
424
755
        }
425
756
 
426
757
        /* Hmm, nothing to do. Let's sleep */
427
 
        if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0)
 
758
        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
428
759
            goto fail;
429
760
 
430
761
        if (ret == 0)
431
762
            goto finish;
432
763
 
433
 
        if (u->fd >= 0) {
 
764
        if (u->rtpoll_item) {
434
765
            struct pollfd *pollfd;
435
766
 
436
767
            pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
460
791
 
461
792
    assert(u);
462
793
 
 
794
    pa_log_debug("caught signal");
 
795
 
463
796
    if (u->sink) {
464
 
        pa_sink_get_volume(u->sink);
465
 
        pa_sink_get_mute(u->sink);
 
797
        pa_sink_get_volume(u->sink, TRUE);
 
798
        pa_sink_get_mute(u->sink, TRUE);
466
799
    }
467
800
 
468
801
    if (u->source)
469
 
        pa_source_get_volume(u->source);
470
 
}
471
 
 
472
 
static int pa_solaris_auto_format(int fd, int mode, pa_sample_spec *ss) {
473
 
    audio_info_t info;
474
 
 
475
 
    AUDIO_INITINFO(&info);
476
 
 
477
 
    if (mode != O_RDONLY) {
478
 
        info.play.sample_rate = ss->rate;
479
 
        info.play.channels = ss->channels;
480
 
        switch (ss->format) {
481
 
        case PA_SAMPLE_U8:
482
 
            info.play.precision = 8;
483
 
            info.play.encoding = AUDIO_ENCODING_LINEAR;
484
 
            break;
485
 
        case PA_SAMPLE_ALAW:
486
 
            info.play.precision = 8;
487
 
            info.play.encoding = AUDIO_ENCODING_ALAW;
488
 
            break;
489
 
        case PA_SAMPLE_ULAW:
490
 
            info.play.precision = 8;
491
 
            info.play.encoding = AUDIO_ENCODING_ULAW;
492
 
            break;
493
 
        case PA_SAMPLE_S16NE:
494
 
            info.play.precision = 16;
495
 
            info.play.encoding = AUDIO_ENCODING_LINEAR;
496
 
            break;
497
 
        default:
498
 
            return -1;
499
 
        }
500
 
    }
501
 
 
502
 
    if (mode != O_WRONLY) {
503
 
        info.record.sample_rate = ss->rate;
504
 
        info.record.channels = ss->channels;
505
 
        switch (ss->format) {
506
 
        case PA_SAMPLE_U8:
507
 
            info.record.precision = 8;
508
 
            info.record.encoding = AUDIO_ENCODING_LINEAR;
509
 
            break;
510
 
        case PA_SAMPLE_ALAW:
511
 
            info.record.precision = 8;
512
 
            info.record.encoding = AUDIO_ENCODING_ALAW;
513
 
            break;
514
 
        case PA_SAMPLE_ULAW:
515
 
            info.record.precision = 8;
516
 
            info.record.encoding = AUDIO_ENCODING_ULAW;
517
 
            break;
518
 
        case PA_SAMPLE_S16NE:
519
 
            info.record.precision = 16;
520
 
            info.record.encoding = AUDIO_ENCODING_LINEAR;
521
 
            break;
522
 
        default:
523
 
            return -1;
524
 
        }
525
 
    }
526
 
 
527
 
    if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
528
 
        if (errno == EINVAL)
529
 
            pa_log("AUDIO_SETINFO: Unsupported sample format.");
530
 
        else
531
 
            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
532
 
        return -1;
533
 
    }
534
 
 
535
 
    return 0;
536
 
}
537
 
 
538
 
static int pa_solaris_set_buffer(int fd, int buffer_size) {
539
 
    audio_info_t info;
540
 
 
541
 
    AUDIO_INITINFO(&info);
542
 
 
543
 
    info.play.buffer_size = buffer_size;
544
 
    info.record.buffer_size = buffer_size;
545
 
 
546
 
    if (ioctl(fd, AUDIO_SETINFO, &info) < 0) {
547
 
        if (errno == EINVAL)
548
 
            pa_log("AUDIO_SETINFO: Unsupported buffer size.");
549
 
        else
550
 
            pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno));
551
 
        return -1;
552
 
    }
553
 
 
554
 
    return 0;
 
802
        pa_source_get_volume(u->source, TRUE);
555
803
}
556
804
 
557
805
int pa__init(pa_module *m) {
558
806
    struct userdata *u = NULL;
559
 
    const char *p;
560
 
    int fd = -1;
561
 
    int buffer_size;
562
 
    int mode;
563
 
    int record = 1, playback = 1;
 
807
    pa_bool_t record = TRUE, playback = TRUE;
564
808
    pa_sample_spec ss;
565
809
    pa_channel_map map;
566
810
    pa_modargs *ma = NULL;
567
 
    char *t;
568
 
    struct pollfd *pollfd;
 
811
    uint32_t buffer_length_msec;
 
812
    int fd;
 
813
    pa_sink_new_data sink_new_data;
 
814
    pa_source_new_data source_new_data;
 
815
    char const *name;
 
816
    char *name_buf;
 
817
    pa_bool_t namereg_fail;
569
818
 
570
819
    pa_assert(m);
571
820
 
575
824
    }
576
825
 
577
826
    if (pa_modargs_get_value_boolean(ma, "record", &record) < 0 || pa_modargs_get_value_boolean(ma, "playback", &playback) < 0) {
578
 
        pa_log("record= and playback= expect numeric argument.");
 
827
        pa_log("record= and playback= expect a boolean argument.");
579
828
        goto fail;
580
829
    }
581
830
 
584
833
        goto fail;
585
834
    }
586
835
 
587
 
    mode = (playback&&record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
 
836
    u = pa_xnew0(struct userdata, 1);
588
837
 
589
 
    buffer_size = 16384;
590
 
    if (pa_modargs_get_value_s32(ma, "buffer_size", &buffer_size) < 0) {
591
 
        pa_log("failed to parse buffer size argument");
592
 
        goto fail;
593
 
    }
 
838
    /*
 
839
     * For a process (or several processes) to use the same audio device for both
 
840
     * record and playback at the same time, the device's mixer must be enabled.
 
841
     * See mixerctl(1). It may be turned off for playback only or record only.
 
842
     */
 
843
    u->mode = (playback && record) ? O_RDWR : (playback ? O_WRONLY : (record ? O_RDONLY : 0));
594
844
 
595
845
    ss = m->core->default_sample_spec;
596
846
    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
597
847
        pa_log("failed to parse sample specification");
598
848
        goto fail;
599
849
    }
600
 
 
601
 
    if ((fd = open(p = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), mode | O_NONBLOCK)) < 0)
602
 
        goto fail;
603
 
 
604
 
    pa_log_info("device opened in %s mode.", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR"));
605
 
 
606
 
    if (pa_solaris_auto_format(fd, mode, &ss) < 0)
607
 
        goto fail;
608
 
 
609
 
    if (pa_solaris_set_buffer(fd, buffer_size) < 0)
610
 
        goto fail;
611
 
 
612
 
    u = pa_xmalloc(sizeof(struct userdata));
 
850
    u->frame_size = pa_frame_size(&ss);
 
851
 
 
852
    u->minimum_request = pa_usec_to_bytes(PA_USEC_PER_SEC / MAX_RENDER_HZ, &ss);
 
853
 
 
854
    buffer_length_msec = 100;
 
855
    if (pa_modargs_get_value_u32(ma, "buffer_length", &buffer_length_msec) < 0) {
 
856
        pa_log("failed to parse buffer_length argument");
 
857
        goto fail;
 
858
    }
 
859
    u->buffer_size = pa_usec_to_bytes(1000 * buffer_length_msec, &ss);
 
860
    if (u->buffer_size < 2 * u->minimum_request) {
 
861
        pa_log("supplied buffer size argument is too small");
 
862
        goto fail;
 
863
    }
 
864
 
 
865
    u->device_name = pa_xstrdup(pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
 
866
 
 
867
    if ((fd = open_audio_device(u, &ss)) < 0)
 
868
        goto fail;
 
869
 
613
870
    u->core = m->core;
614
 
 
615
 
    u->fd = fd;
616
 
 
617
 
    pa_memchunk_reset(&u->memchunk);
618
 
 
619
 
    /* We use this to get a reasonable chunk size */
620
 
    u->page_size = PA_PAGE_SIZE;
621
 
 
622
 
    u->frame_size = pa_frame_size(&ss);
623
 
    u->buffer_size = buffer_size;
624
 
 
625
 
    u->written_bytes = 0;
626
 
    u->read_bytes = 0;
627
 
 
628
871
    u->module = m;
629
872
    m->userdata = u;
630
873
 
631
 
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
 
874
    pa_memchunk_reset(&u->memchunk);
632
875
 
633
876
    u->rtpoll = pa_rtpoll_new();
634
 
    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
635
 
 
636
 
    pa_rtpoll_set_timer_periodic(u->rtpoll, pa_bytes_to_usec(u->buffer_size / 10, &ss));
637
 
 
638
 
    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
639
 
    pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
640
 
    pollfd->fd = fd;
641
 
    pollfd->events = 0;
642
 
    pollfd->revents = 0;
643
 
 
644
 
    if (mode != O_WRONLY) {
645
 
        u->source = pa_source_new(m->core, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, &map);
646
 
        pa_assert(u->source);
 
877
    pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
 
878
 
 
879
    u->rtpoll_item = NULL;
 
880
    build_pollfd(u);
 
881
 
 
882
    if (u->mode != O_WRONLY) {
 
883
        name_buf = NULL;
 
884
        namereg_fail = TRUE;
 
885
 
 
886
        if (!(name = pa_modargs_get_value(ma, "source_name", NULL))) {
 
887
            name = name_buf = pa_sprintf_malloc("solaris_input.%s", pa_path_get_filename(u->device_name));
 
888
            namereg_fail = FALSE;
 
889
        }
 
890
 
 
891
        pa_source_new_data_init(&source_new_data);
 
892
        source_new_data.driver = __FILE__;
 
893
        source_new_data.module = m;
 
894
        pa_source_new_data_set_name(&source_new_data, name);
 
895
        source_new_data.namereg_fail = namereg_fail;
 
896
        pa_source_new_data_set_sample_spec(&source_new_data, &ss);
 
897
        pa_source_new_data_set_channel_map(&source_new_data, &map);
 
898
        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
 
899
        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
 
900
        pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM source");
 
901
        pa_proplist_sets(source_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");
 
902
        pa_proplist_setf(source_new_data.proplist, PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE, "%lu", (unsigned long) u->buffer_size);
 
903
 
 
904
        u->source = pa_source_new(m->core, &source_new_data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL);
 
905
        pa_source_new_data_done(&source_new_data);
 
906
        pa_xfree(name_buf);
 
907
 
 
908
        if (!u->source) {
 
909
            pa_log("Failed to create source object");
 
910
            goto fail;
 
911
        }
647
912
 
648
913
        u->source->userdata = u;
649
914
        u->source->parent.process_msg = source_process_msg;
650
915
 
651
 
        pa_source_set_module(u->source, m);
652
 
        pa_source_set_description(u->source, t = pa_sprintf_malloc("Solaris PCM on '%s'", p));
653
 
        pa_xfree(t);
654
916
        pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
655
917
        pa_source_set_rtpoll(u->source, u->rtpoll);
656
918
 
657
 
        u->source->flags = PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY|PA_SOURCE_HW_VOLUME_CTRL;
658
 
        u->source->refresh_volume = 1;
 
919
        u->source->get_volume = source_get_volume;
 
920
        u->source->set_volume = source_set_volume;
 
921
        u->source->refresh_volume = TRUE;
659
922
    } else
660
923
        u->source = NULL;
661
924
 
662
 
    if (mode != O_RDONLY) {
663
 
        u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map);
 
925
    if (u->mode != O_RDONLY) {
 
926
        name_buf = NULL;
 
927
        namereg_fail = TRUE;
 
928
        if (!(name = pa_modargs_get_value(ma, "sink_name", NULL))) {
 
929
            name = name_buf = pa_sprintf_malloc("solaris_output.%s", pa_path_get_filename(u->device_name));
 
930
            namereg_fail = FALSE;
 
931
        }
 
932
 
 
933
        pa_sink_new_data_init(&sink_new_data);
 
934
        sink_new_data.driver = __FILE__;
 
935
        sink_new_data.module = m;
 
936
        pa_sink_new_data_set_name(&sink_new_data, name);
 
937
        sink_new_data.namereg_fail = namereg_fail;
 
938
        pa_sink_new_data_set_sample_spec(&sink_new_data, &ss);
 
939
        pa_sink_new_data_set_channel_map(&sink_new_data, &map);
 
940
        pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_STRING, u->device_name);
 
941
        pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_API, "solaris");
 
942
        pa_proplist_setf(sink_new_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Solaris PCM sink");
 
943
        pa_proplist_sets(sink_new_data.proplist, PA_PROP_DEVICE_ACCESS_MODE, "serial");
 
944
 
 
945
        u->sink = pa_sink_new(m->core, &sink_new_data, PA_SINK_HARDWARE|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL|PA_SINK_HW_MUTE_CTRL);
 
946
        pa_sink_new_data_done(&sink_new_data);
 
947
 
664
948
        pa_assert(u->sink);
665
 
 
666
949
        u->sink->userdata = u;
667
950
        u->sink->parent.process_msg = sink_process_msg;
668
951
 
669
 
        pa_sink_set_module(u->sink, m);
670
 
        pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Solaris PCM on '%s'", p));
671
 
        pa_xfree(t);
672
952
        pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
673
953
        pa_sink_set_rtpoll(u->sink, u->rtpoll);
674
954
 
675
 
        u->sink->flags = PA_SINK_HARDWARE|PA_SINK_LATENCY|PA_SINK_HW_VOLUME_CTRL;
676
 
        u->sink->refresh_volume = 1;
677
 
        u->sink->refresh_mute = 1;
 
955
        u->sink->get_volume = sink_get_volume;
 
956
        u->sink->set_volume = sink_set_volume;
 
957
        u->sink->get_mute = sink_get_mute;
 
958
        u->sink->set_mute = sink_set_mute;
 
959
        u->sink->refresh_volume = u->sink->refresh_muted = TRUE;
 
960
 
 
961
        pa_sink_set_max_request(u->sink, u->buffer_size);
 
962
        pa_sink_set_max_rewind(u->sink, u->buffer_size);
678
963
    } else
679
964
        u->sink = NULL;
680
965
 
681
966
    pa_assert(u->source || u->sink);
682
967
 
683
968
    u->sig = pa_signal_new(SIGPOLL, sig_callback, u);
684
 
    pa_assert(u->sig);
685
 
    ioctl(u->fd, I_SETSIG, S_MSG);
 
969
    if (u->sig)
 
970
        ioctl(u->fd, I_SETSIG, S_MSG);
 
971
    else
 
972
        pa_log_warn("Could not register SIGPOLL handler");
686
973
 
687
974
    if (!(u->thread = pa_thread_new(thread_func, u))) {
688
975
        pa_log("Failed to create thread.");
690
977
    }
691
978
 
692
979
    /* Read mixer settings */
693
 
    if (u->source)
694
 
        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->source), PA_SOURCE_MESSAGE_GET_VOLUME, &u->source->volume, 0, NULL);
695
980
    if (u->sink) {
696
 
        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_VOLUME, &u->sink->volume, 0, NULL);
697
 
        pa_asyncmsgq_send(u->thread_mq.inq, PA_MSGOBJECT(u->sink), PA_SINK_MESSAGE_GET_MUTE, &u->sink->muted, 0, NULL);
698
 
    }
699
 
 
700
 
    if (u->sink)
 
981
        if (sink_new_data.volume_is_set)
 
982
            u->sink->set_volume(u->sink);
 
983
        else
 
984
            u->sink->get_volume(u->sink);
 
985
 
 
986
        if (sink_new_data.muted_is_set)
 
987
            u->sink->set_mute(u->sink);
 
988
        else
 
989
            u->sink->get_mute(u->sink);
 
990
 
701
991
        pa_sink_put(u->sink);
702
 
    if (u->source)
 
992
    }
 
993
 
 
994
    if (u->source) {
 
995
        if (source_new_data.volume_is_set)
 
996
            u->source->set_volume(u->source);
 
997
        else
 
998
            u->source->get_volume(u->source);
 
999
 
703
1000
        pa_source_put(u->source);
 
1001
    }
704
1002
 
705
1003
    pa_modargs_free(ma);
706
1004
 
726
1024
    if (!(u = m->userdata))
727
1025
        return;
728
1026
 
729
 
    ioctl(u->fd, I_SETSIG, 0);
730
 
    pa_signal_free(u->sig);
 
1027
    if (u->sig) {
 
1028
        ioctl(u->fd, I_SETSIG, 0);
 
1029
        pa_signal_free(u->sig);
 
1030
    }
731
1031
 
732
1032
    if (u->sink)
733
1033
        pa_sink_unlink(u->sink);
748
1048
    if (u->source)
749
1049
        pa_source_unref(u->source);
750
1050
 
751
 
     if (u->memchunk.memblock)
 
1051
    if (u->memchunk.memblock)
752
1052
        pa_memblock_unref(u->memchunk.memblock);
753
1053
 
754
1054
    if (u->rtpoll_item)
760
1060
    if (u->fd >= 0)
761
1061
        close(u->fd);
762
1062
 
 
1063
    pa_xfree(u->device_name);
 
1064
 
763
1065
    pa_xfree(u);
764
1066
}