2 * ossp-padsp - ossp DSP slave which forwards to pulseaduio
4 * Copyright (C) 2008-2010 SUSE Linux Products GmbH
5 * Copyright (C) 2008-2010 Tejun Heo <tj@kernel.org>
7 * This file is released under the GPLv2.
23 #include <sys/types.h>
26 #include <pulse/pulseaudio.h>
27 #include <sys/soundcard.h>
29 #include "ossp-slave.h"
32 AFMT_FLOAT = 0x00004000,
33 AFMT_S32_LE = 0x00001000,
34 AFMT_S32_BE = 0x00002000,
37 /* everything is in millisecs */
38 struct stream_params {
49 /* TODO: make this configurable */
50 static struct stream_params stream_params[] = {
51 [ PLAY ] = { .min_process = 25, .min_latency = 100,
52 .dfl_process = 50, .dfl_latency = 200,
53 .mmap_process = 25, .mmap_latency = 50,
54 .mmap_lead = 25, .mmap_staging = 100 },
55 [ REC ] = { .min_process = 25, .min_latency = 200,
56 .dfl_process = 50, .dfl_latency = 400,
57 .mmap_process = 25, .mmap_latency = 50,
58 .mmap_lead = 25, .mmap_staging = 1000 },
61 static size_t page_size;
62 static pa_context *context;
63 static pa_threaded_mainloop *mainloop;
64 static pa_mainloop_api *mainloop_api;
65 static char stream_name[128];
66 static int stream_enabled[2];
67 static int stream_corked[2];
68 static int stream_waiting;
69 static int stream_notify;
70 static pa_channel_map channel_map_stor;
71 static pa_channel_map *channel_map;
72 static pa_stream *stream[2];
73 static pa_usec_t stream_ptr_timestamp[2];
74 static struct ring_buf rec_buf;
75 static int stored_oss_vol[2][2] = { { -1, -1 }, { -1, -1 } };
78 static pa_sample_spec sample_spec = {
79 .format = PA_SAMPLE_U8,
83 static size_t sample_bps = 8000;
84 static size_t frame_size = 1;
86 /* user visible stream parameters */
87 static size_t user_frag_size;
88 static size_t user_subdivision; /* alternative way to determine frag_size */
89 static size_t user_max_frags; /* maximum number of fragments */
90 static size_t user_max_length;
92 /* actual stream parameters */
93 static size_t frag_size;
94 static size_t target_length;
95 static size_t max_length;
96 static size_t prebuf_size;
99 static size_t mmap_raw_size, mmap_size;
100 static void *mmap_map[2];
101 static uint64_t mmap_idx[2]; /* mmap pointer */
102 static uint64_t mmap_last_idx[2]; /* last idx for get_ptr */
103 static struct ring_buf mmap_stg[2]; /* staging ring buffer */
104 static size_t mmap_lead[2]; /* lead bytes */
105 static int mmap_sync[2]; /* sync with backend stream */
107 static const char *dir_str[] = {
112 static void stream_rw_callback(pa_stream *s, size_t length, void *userdata);
114 #define __pa_err pa_strerror(pa_context_errno(context))
115 #define dbg1_pa(fmt, args...) dbg1(fmt" (%s)" , ##args, __pa_err)
116 #define dbg0_pa(fmt, args...) dbg0(fmt" (%s)" , ##args, __pa_err)
117 #define info_pa(fmt, args...) info(fmt" (%s)" , ##args, __pa_err)
118 #define warn_pa(fmt, args...) warn(fmt" (%s)" , ##args, __pa_err)
119 #define err_pa(fmt, args...) err(fmt" (%s)" , ##args, __pa_err)
121 #define round_down(v, t) ((v) / (t) * (t))
122 #define round_up(v, t) (((v) + (t) - 1) / (t) * (t))
123 #define is_power2(v) !((v) & ((v) - 1))
125 static int do_mixer(int dir, int *vol);
127 static int padsp_done(void)
130 mainloop_api->quit(mainloop_api, 1);
134 static int fmt_oss_to_pa(int fmt)
137 case AFMT_U8: return PA_SAMPLE_U8;
138 case AFMT_A_LAW: return PA_SAMPLE_ALAW;
139 case AFMT_MU_LAW: return PA_SAMPLE_ULAW;
140 case AFMT_S16_LE: return PA_SAMPLE_S16LE;
141 case AFMT_S16_BE: return PA_SAMPLE_S16BE;
142 case AFMT_FLOAT: return PA_SAMPLE_FLOAT32NE;
143 case AFMT_S32_LE: return PA_SAMPLE_S32LE;
144 case AFMT_S32_BE: return PA_SAMPLE_S32BE;
145 default: return PA_SAMPLE_U8;
149 static int fmt_pa_to_oss(int fmt)
152 case PA_SAMPLE_U8: return AFMT_U8;
153 case PA_SAMPLE_ALAW: return AFMT_A_LAW;
154 case PA_SAMPLE_ULAW: return AFMT_MU_LAW;
155 case PA_SAMPLE_S16LE: return AFMT_S16_LE;
156 case PA_SAMPLE_S16BE: return AFMT_S16_BE;
157 case PA_SAMPLE_FLOAT32NE: return AFMT_FLOAT;
158 case PA_SAMPLE_S32LE: return AFMT_S32_LE;
159 case PA_SAMPLE_S32BE: return AFMT_S32_BE;
160 default: return AFMT_U8;
164 #define EXEC_OP(op, args...) do { \
168 while (pa_operation_get_state(_o) != PA_OPERATION_DONE) \
169 pa_threaded_mainloop_wait(mainloop); \
170 pa_operation_unref(_o); \
173 static void context_op_callback(pa_context *s, int success, void *userdata)
175 *(int *)userdata = success;
176 pa_threaded_mainloop_signal(mainloop, 0);
179 static void stream_op_callback(pa_stream *s, int success, void *userdata)
181 *(int *)userdata = success;
182 pa_threaded_mainloop_signal(mainloop, 0);
185 #define EXEC_CONTEXT_OP(op, args...) ({ \
187 EXEC_OP(op , ##args, context_op_callback, &_success); \
189 warn_pa("%s() failed", #op); \
190 _success ? 0 : -EIO; })
192 #define EXEC_STREAM_OP(op, args...) ({ \
194 EXEC_OP(op , ##args, stream_op_callback, &_success); \
196 warn_pa("%s() failed", #op); \
197 _success ? 0 : -EIO; })
199 static int mmapped(void)
201 return mmap_map[PLAY] || mmap_map[REC];
204 static uint64_t get_mmap_idx(int dir)
210 return mmap_idx[dir];
212 if (pa_stream_get_time(stream[dir], &time) < 0) {
213 dbg1_pa("pa_stream_get_time() failed");
214 return mmap_idx[dir];
217 /* calculate the current index from time elapsed */
218 idx = ((uint64_t)time * sample_bps / 1000000);
219 /* round down to the nearest frame boundary */
220 idx = idx / frame_size * frame_size;
225 static void flush_streams(int drain)
229 if (!(stream[PLAY] || stream[REC]))
232 dbg0("FLUSH drain=%d", drain);
234 /* mmapped streams run forever, can't drain */
235 if (drain && !mmapped() && stream[PLAY])
236 EXEC_STREAM_OP(pa_stream_drain, stream[PLAY]);
238 for (i = 0; i < 2; i++)
240 EXEC_STREAM_OP(pa_stream_flush, stream[i]);
242 ring_consume(&rec_buf, ring_bytes(&rec_buf));
245 static void kill_streams(void)
249 if (!(stream[PLAY] || stream[REC]))
256 for (dir = 0; dir < 2; dir++) {
259 pa_stream_disconnect(stream[dir]);
260 pa_stream_unref(stream[dir]);
262 stream_ptr_timestamp[dir] = 0;
264 ring_consume(&mmap_stg[dir], ring_bytes(&mmap_stg[dir]));
265 ring_resize(&mmap_stg[dir], 0);
269 static int trigger_streams(int play, int rec)
271 int ret = 0, dir, rc;
274 stream_corked[PLAY] = !play;
276 stream_corked[REC] = !rec;
278 for (dir = 0; dir < 2; dir++) {
282 rc = EXEC_STREAM_OP(pa_stream_cork, stream[dir],
284 if (!rc && dir == PLAY && !mmap_map[dir] && !stream_corked[dir])
285 rc = EXEC_STREAM_OP(pa_stream_trigger, stream[dir]);
293 static void stream_state_callback(pa_stream *s, void *userdata)
295 pa_threaded_mainloop_signal(mainloop, 0);
298 static void stream_underflow_callback(pa_stream *s, void *userdata)
300 int dir = (s == stream[PLAY]) ? PLAY : REC;
302 dbg0("%s stream underrun", dir_str[dir]);
305 static void stream_overflow_callback(pa_stream *s, void *userdata)
307 int dir = (s == stream[PLAY]) ? PLAY : REC;
309 dbg0("%s stream overrun", dir_str[dir]);
312 static size_t duration_to_bytes(size_t dur)
314 return round_up(dur * sample_bps / 1000, frame_size);
317 static int prepare_streams(void)
319 const struct stream_params *sp;
320 size_t min_frag_size, min_target_length, tmp;
324 if ((!stream_enabled[PLAY] || stream[PLAY]) &&
325 (!stream_enabled[REC] || stream[REC]))
328 /* determine sample parameters */
329 sample_bps = pa_bytes_per_second(&sample_spec);
330 frame_size = pa_frame_size(&sample_spec);
332 sp = &stream_params[PLAY];
333 if (stream_enabled[REC])
334 sp = &stream_params[REC];
336 min_frag_size = duration_to_bytes(sp->min_process);
337 min_target_length = duration_to_bytes(sp->min_latency);
339 /* determine frag_size */
340 if (user_frag_size % frame_size) {
341 warn("requested frag_size (%zu) isn't multiple of frame (%zu)",
342 user_frag_size, frame_size);
343 user_frag_size = round_up(user_frag_size, frame_size);
346 if (user_subdivision)
347 user_frag_size = round_up(sample_bps / user_subdivision,
350 if (user_frag_size) {
351 frag_size = user_frag_size;
352 if (frag_size < min_frag_size) {
353 dbg0("requested frag_size (%zu) is smaller than "
354 "minimum (%zu)", frag_size, min_frag_size);
355 frag_size = min_frag_size;
358 tmp = round_up(sp->dfl_process * sample_bps / 1000, frame_size);
360 /* if frame_size is power of two, make frag_size so too */
361 if (is_power2(frame_size)) {
362 frag_size = frame_size;
363 while (frag_size < tmp)
366 user_frag_size = frag_size;
369 /* determine target and max length */
370 if (user_max_frags) {
371 target_length = user_max_frags * user_frag_size;
372 if (target_length < min_target_length) {
373 dbg0("requested target_length (%zu) is smaller than "
374 "minimum (%zu)", target_length, min_target_length);
375 target_length = min_target_length;
378 tmp = round_up(sp->dfl_latency * sample_bps / 1000, frag_size);
380 /* if frag_size is power of two, make target_length so
381 * too and align it to page_size.
383 if (is_power2(frag_size)) {
384 target_length = frag_size;
385 while (target_length < max(tmp, page_size))
388 user_max_frags = target_length / frag_size;
391 user_max_length = user_frag_size * user_max_frags;
392 max_length = target_length + 2 * frag_size;
394 /* If mmapped, create backend stream with fixed parameters to
395 * create illusion of hardware buffer with acceptable latency.
398 /* set parameters for backend streams */
399 frag_size = duration_to_bytes(sp->mmap_process);
400 target_length = duration_to_bytes(sp->mmap_latency);
401 max_length = target_length + frag_size;
404 mmap_size = round_down(mmap_raw_size, frame_size);
405 if (mmap_size != mmap_raw_size)
406 warn("mmap_raw_size (%zu) unaligned to frame_size "
407 "(%zu), mmap_size adjusted to %zu",
408 mmap_raw_size, frame_size, mmap_size);
410 prebuf_size = min(user_frag_size * 2, user_max_length / 2);
411 prebuf_size = round_down(prebuf_size, frame_size);
414 for (dir = 0; dir < 2; dir++) {
415 pa_buffer_attr new_ba = { };
418 pa_stream_flags_t flags;
422 if (!stream_enabled[dir] || stream[dir])
425 dbg0("CREATE %s %s fsz=%zu:%zu", dir_str[dir],
426 pa_sample_spec_snprint(buf, sizeof(buf), &sample_spec),
427 frag_size, frag_size * 1000 / sample_bps);
428 dbg0(" tlen=%zu:%zu max=%zu:%zu pre=%zu:%zu",
429 target_length, target_length * 1000 / sample_bps,
430 max_length, max_length * 1000 / sample_bps,
431 prebuf_size, prebuf_size * 1000 / sample_bps);
432 dbg0(" u_sd=%zu u_fsz=%zu:%zu u_maxf=%zu",
433 user_subdivision, user_frag_size,
434 user_frag_size * 1000 / sample_bps, user_max_frags);
436 channel_map = pa_channel_map_init_auto(&channel_map_stor,
437 sample_spec.channels,
440 s = pa_stream_new(context, stream_name, &sample_spec,
443 err_pa("can't create streams");
448 pa_stream_set_state_callback(s, stream_state_callback, NULL);
450 pa_stream_set_write_callback(s,
451 stream_rw_callback, NULL);
452 pa_stream_set_underflow_callback(s,
453 stream_underflow_callback, NULL);
455 pa_stream_set_read_callback(s,
456 stream_rw_callback, NULL);
457 pa_stream_set_overflow_callback(s,
458 stream_overflow_callback, NULL);
461 flags = PA_STREAM_AUTO_TIMING_UPDATE |
462 PA_STREAM_INTERPOLATE_TIMING;
463 if (stream_corked[dir])
464 flags |= PA_STREAM_START_CORKED;
466 new_ba.maxlength = max_length;
467 new_ba.tlength = target_length;
468 new_ba.prebuf = prebuf_size;
469 new_ba.minreq = frag_size;
470 new_ba.fragsize = frag_size;
473 if (pa_stream_connect_playback(s, NULL, &new_ba, flags,
475 err_pa("failed to connect playback stream");
479 if (pa_stream_connect_record(s, NULL, &new_ba, flags)) {
480 err_pa("failed to connect record stream");
485 while (pa_stream_get_state(s) == PA_STREAM_CREATING)
486 pa_threaded_mainloop_wait(mainloop);
487 if (pa_stream_get_state(s) != PA_STREAM_READY) {
488 err_pa("failed to connect stream (state=%d)",
489 pa_stream_get_state(s));
493 /* apply stored OSS volume */
494 memcpy(vol, stored_oss_vol[dir], sizeof(vol));
495 if (do_mixer(dir, vol))
496 warn_pa("initial volume control failed");
498 /* stream is ready setup mmap stuff */
502 /* prep mmap staging buffer */
503 size = round_up(sp->mmap_staging * sample_bps / 1000,
505 rc = ring_resize(&mmap_stg[dir], size);
509 mmap_idx[dir] = mmap_last_idx[dir] = get_mmap_idx(dir);
510 mmap_lead[dir] = round_up(sp->mmap_lead * sample_bps / 1000,
514 /* apply the current trigger settings */
515 trigger_streams(-1, -1);
528 static void play_volume_callback(pa_context *c, const pa_sink_input_info *i,
529 int eol, void *userdata)
531 struct volume_ret *vr = userdata;
537 pa_threaded_mainloop_signal(mainloop, 0);
540 static void rec_volume_callback(pa_context *c, const pa_source_info *i,
541 int eol, void *userdata)
543 struct volume_ret *vr = userdata;
549 pa_threaded_mainloop_signal(mainloop, 0);
552 static int get_volume(int dir, pa_cvolume *cv)
554 struct volume_ret vr = { .cv = cv };
558 idx = pa_stream_get_index(stream[PLAY]);
559 EXEC_OP(pa_context_get_sink_input_info,
560 context, idx, play_volume_callback, &vr);
562 idx = pa_stream_get_device_index(stream[REC]);
563 EXEC_OP(pa_context_get_source_info_by_index,
564 context, idx, rec_volume_callback, &vr);
567 warn_pa("failed to get %s volume", dir_str[dir]);
573 static int set_volume(int dir, pa_cvolume *cv)
579 idx = pa_stream_get_index(stream[PLAY]);
580 rc = EXEC_CONTEXT_OP(pa_context_set_sink_input_volume,
583 idx = pa_stream_get_device_index(stream[REC]);
584 rc = EXEC_CONTEXT_OP(pa_context_set_source_volume_by_index,
590 static int chan_left_right(int ch)
592 if (!channel_map || channel_map->channels <= ch) {
603 switch (channel_map->map[ch]) {
604 /*case PA_CHANNEL_POSITION_LEFT:*/ /* same as FRONT_LEFT */
605 case PA_CHANNEL_POSITION_FRONT_LEFT:
606 case PA_CHANNEL_POSITION_REAR_LEFT:
607 case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
608 case PA_CHANNEL_POSITION_SIDE_LEFT:
609 case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
610 case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
612 /*case PA_CHANNEL_POSITION_RIGHT:*/ /* same as FRONT_RIGHT */
613 case PA_CHANNEL_POSITION_FRONT_RIGHT:
614 case PA_CHANNEL_POSITION_REAR_RIGHT:
615 case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
616 case PA_CHANNEL_POSITION_SIDE_RIGHT:
617 case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
618 case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
625 static int do_mixer(int dir, int *vol)
634 stored_oss_vol[dir][LEFT] = vol[LEFT];
635 stored_oss_vol[dir][RIGHT] = vol[RIGHT];
636 vol[LEFT] = vol[LEFT] * PA_VOLUME_NORM / 100;
637 vol[RIGHT] = vol[RIGHT] * PA_VOLUME_NORM / 100;
638 avg = (vol[LEFT] + vol[RIGHT]) / 2;
640 pa_cvolume_mute(&cv, sample_spec.channels);
642 for (i = 0; i < cv.channels; i++)
643 switch (chan_left_right(i)) {
644 case LEFT: cv.values[i] = vol[LEFT]; break;
645 case RIGHT: cv.values[i] = vol[RIGHT]; break;
646 default: cv.values[i] = avg; break;
649 rc = set_volume(dir, &cv);
654 rc = get_volume(dir, &cv);
658 if (cv.channels == 1)
659 lv = rv = pa_cvolume_avg(&cv);
661 unsigned lcnt = 0, rcnt = 0;
663 for (i = 0, lv = 0, rv = 0; i < cv.channels; i++)
664 switch (chan_left_right(i)) {
665 case LEFT: lv += cv.values[i]; lcnt++; break;
666 case RIGHT: rv += cv.values[i]; rcnt++; break;
675 vol[LEFT] = lv * 100 / PA_VOLUME_NORM;
676 vol[RIGHT] = rv * 100 / PA_VOLUME_NORM;
681 static ssize_t padsp_mixer(enum ossp_opcode opcode,
682 void *carg, void *din, size_t din_sz,
683 void *rarg, void *dout, size_t *dout_szp, int tfd)
685 struct ossp_mixer_arg *arg = carg;
688 if (prepare_streams())
691 for (i = 0; i < 2; i++)
693 rc[i] = do_mixer(i, arg->vol[i]);
695 memset(arg->vol[i], -1, sizeof(arg->vol[i]));
697 *(struct ossp_mixer_arg *)rarg = *arg;
698 return rc[0] ?: rc[1];
701 static void context_state_callback(pa_context *cxt, void *userdata)
703 pa_threaded_mainloop_signal(mainloop, 0);
706 static void context_subscribe_callback(pa_context *context,
707 pa_subscription_event_type_t type,
708 uint32_t idx, void *userdata)
710 struct ossp_notify event = { .magic = OSSP_NOTIFY_MAGIC,
711 .opcode = OSSP_NOTIFY_VOLCHG };
714 if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) !=
715 PA_SUBSCRIPTION_EVENT_CHANGE)
718 ret = write(ossp_notify_fd, &event, sizeof(event));
719 if (ret != sizeof(event) && errno != EPIPE)
720 warn_e(-errno, "write to notify_fd failed");
723 static ssize_t padsp_open(enum ossp_opcode opcode,
724 void *carg, void *din, size_t din_sz,
725 void *rarg, void *dout, size_t *dout_szp, int tfd)
727 struct ossp_dsp_open_arg *arg = carg;
728 char host_name[128] = "(unknown)", opener[128] = "(unknown)";
731 switch (arg->flags & O_ACCMODE) {
733 stream_enabled[PLAY] = 1;
736 stream_enabled[REC] = 1;
739 stream_enabled[PLAY] = 1;
740 stream_enabled[REC] = 1;
746 /* determine stream name */
747 gethostname(host_name, sizeof(host_name) - 1);
748 snprintf(stream_name, sizeof(stream_name), "OSS Proxy %s/%s:%ld",
749 host_name, ossp_user_name, (long)arg->opener_pid);
751 /* create and connect PA context */
752 get_proc_self_info(arg->opener_pid, NULL, opener, sizeof(opener));
753 context = pa_context_new(mainloop_api, opener);
755 err("pa_context_new() failed");
759 pa_context_set_state_callback(context, context_state_callback, NULL);
760 pa_context_set_subscribe_callback(context, context_subscribe_callback,
763 pa_context_connect(context, NULL, 0, NULL);
765 state = pa_context_get_state(context);
766 if (state != PA_CONTEXT_CONNECTING &&
767 state != PA_CONTEXT_AUTHORIZING &&
768 state != PA_CONTEXT_SETTING_NAME)
771 pa_threaded_mainloop_wait(mainloop);
774 if (EXEC_CONTEXT_OP(pa_context_subscribe, context,
775 PA_SUBSCRIPTION_MASK_SINK_INPUT |
776 PA_SUBSCRIPTION_MASK_SOURCE))
777 warn_pa("failed to subscribe to context events");
779 if (state != PA_CONTEXT_READY) {
780 err_pa("failed to connect context, state=%d", state);
787 static void mmap_fill_pstg(void)
789 struct ring_buf *stg = &mmap_stg[PLAY];
790 struct ring_buf mmap;
791 uint64_t new_idx = get_mmap_idx(PLAY);
792 size_t bytes, space, size;
795 if (new_idx <= mmap_idx[PLAY])
798 bytes = new_idx - mmap_idx[PLAY];
799 space = ring_space(stg);
801 if (bytes > mmap_size) {
802 dbg0("mmap playback transfer chunk bigger than "
803 "mmap size (bytes=%zu mmap_size=%zu)", bytes, mmap_size);
809 dbg0("mmap playback staging buffer overflow "
810 "(bytes=%zu space=%zu)", bytes, space);
815 ring_manual_init(&mmap, mmap_map[PLAY], mmap_size,
816 new_idx % mmap_size, bytes);
818 while ((data = ring_data(&mmap, &size))) {
819 ring_fill(stg, data, size);
820 ring_consume(&mmap, size);
823 mmap_idx[PLAY] = new_idx;
826 static void mmap_consume_rstg(void)
828 struct ring_buf *stg = &mmap_stg[REC];
829 struct ring_buf mmap;
830 uint64_t new_idx = get_mmap_idx(REC);
831 uint64_t fill_idx = mmap_idx[REC];
834 if (new_idx <= mmap_idx[REC])
837 space = new_idx - mmap_idx[REC]; /* mmapped space to fill in */
838 bytes = ring_bytes(stg); /* recorded bytes in staging */
842 dbg0("mmap recording staging buffer underflow "
843 "(space=%zu bytes=%zu)", space, bytes);
847 if (space > mmap_size) {
849 dbg0("mmap recording transfer chunk bigger than "
850 "mmap size (space=%zu mmap_size=%zu)",
856 /* If resync is requested, leave lead bytes in the staging
857 * buffer and copy everything else such that data is filled
858 * upto the new_idx. If there are more bytes in staging than
859 * available space, those will be dropped.
861 if (mmap_sync[REC]) {
862 ssize_t avail = bytes - mmap_lead[REC];
864 /* make sure we always have lead bytes in staging */
869 dbg0("dropping %zu bytes from record staging buffer",
871 ring_consume(&mmap_stg[REC], avail - space);
874 dbg0("skippping %zu bytes in record mmap map",
879 assert(new_idx >= avail);
880 fill_idx = new_idx - avail;
884 ring_manual_init(&mmap, mmap_map[REC], mmap_size,
885 fill_idx % mmap_size, 0);
891 data = ring_data(stg, &size);
894 todo = min(size, space);
895 ring_fill(&mmap, data, todo);
897 ring_consume(stg, todo);
902 mmap_idx[REC] = new_idx;
905 static void do_mmap_write(size_t space)
907 struct ring_buf *stg = &mmap_stg[PLAY];
911 space = round_down(space, frame_size);
914 while (space && (data = ring_data(stg, &todo))) {
915 pa_seek_mode_t mode = PA_SEEK_RELATIVE_END;
918 todo = min(todo, space);
920 if (mmap_sync[PLAY]) {
921 mode = PA_SEEK_RELATIVE_ON_READ;
922 offset = (int64_t)mmap_lead[PLAY] - ring_bytes(stg);
923 dbg0("mmap resync, offset=%ld", (long)offset);
926 if (pa_stream_write(stream[PLAY], data, todo, NULL,
928 err_pa("pa_stream_write() failed");
934 ring_consume(stg, todo);
939 static void do_mmap_read(size_t bytes)
941 struct ring_buf *stg = &mmap_stg[REC];
943 bytes = round_down(bytes, frame_size);
947 const void *peek_data;
950 if (pa_stream_peek(stream[REC], &peek_data, &size)) {
951 err_pa("pa_stream_peek() failed");
959 if (size <= ring_space(stg))
960 ring_fill(stg, peek_data, size);
963 dbg0("recording staging buffer overflow, "
964 "requesting resync");
968 pa_stream_drop(stream[REC]);
973 static void stream_rw_callback(pa_stream *s, size_t length, void *userdata)
978 if (s == stream[PLAY]) {
980 size = pa_stream_writable_size(s);
983 } else if (s == stream[REC]) {
985 size = pa_stream_readable_size(s);
989 dbg0("stream_rw_callback(): unknown stream %p PLAY/REC=%p/%p\n",
990 s, stream[PLAY], stream[REC]);
994 if (size < user_frag_size)
997 pa_threaded_mainloop_signal(mainloop, 0);
999 struct ossp_notify event = { .magic = OSSP_NOTIFY_MAGIC,
1000 .opcode = OSSP_NOTIFY_POLL };
1003 ret = write(ossp_notify_fd, &event, sizeof(event));
1004 if (ret != sizeof(event)) {
1006 err_e(-errno, "write to notify_fd failed");
1008 /* This function is run from PA mainloop and
1009 * thus the following padsp_done() won't be
1010 * noticed before the mainthread tries to run
1011 * the next command. Well, that's good enough.
1019 static ssize_t padsp_write(enum ossp_opcode opcode,
1020 void *carg, void *din, size_t din_sz,
1021 void *rarg, void *dout, size_t *dout_szp, int tfd)
1023 struct ossp_dsp_rw_arg *arg = carg;
1026 if (prepare_streams() || !stream[PLAY])
1031 size = pa_stream_writable_size(stream[PLAY]);
1032 if (arg->nonblock || size >= user_frag_size)
1034 pa_threaded_mainloop_wait(mainloop);
1038 size = round_down(size, user_frag_size);
1042 size = min(size, din_sz);
1044 if (pa_stream_write(stream[PLAY], din, size, NULL,
1045 0, PA_SEEK_RELATIVE) < 0) {
1046 err_pa("pa_stream_write() failed");
1047 return padsp_done();
1053 static ssize_t padsp_read(enum ossp_opcode opcode,
1054 void *carg, void *din, size_t din_sz,
1055 void *rarg, void *dout, size_t *dout_szp, int tfd)
1057 struct ossp_dsp_rw_arg *arg = carg;
1061 if (prepare_streams() || !stream[REC])
1064 if (!arg->nonblock) {
1067 size = pa_stream_readable_size(stream[REC]);
1068 if (size + ring_bytes(&rec_buf) >= user_frag_size)
1070 pa_threaded_mainloop_wait(mainloop);
1075 while (ring_bytes(&rec_buf) < max(user_frag_size, *dout_szp)) {
1076 const void *peek_data;
1078 if (pa_stream_peek(stream[REC], &peek_data, &size) < 0) {
1079 err_pa("pa_stream_peek() failed");
1080 return padsp_done();
1086 if (ring_space(&rec_buf) < size) {
1089 bufsz = ring_size(&rec_buf);
1090 bufsz = max(2 * bufsz, bufsz + 2 * size);
1092 if (ring_resize(&rec_buf, bufsz)) {
1093 err("failed to allocate recording buffer");
1094 return padsp_done();
1098 ring_fill(&rec_buf, peek_data, size);
1099 pa_stream_drop(stream[REC]);
1102 size = round_down(ring_bytes(&rec_buf), user_frag_size);
1110 *dout_szp = size = min(size, *dout_szp);
1115 data = ring_data(&rec_buf, &cnt);
1118 cnt = min(size, cnt);
1119 memcpy(dout, data, cnt);
1120 ring_consume(&rec_buf, cnt);
1128 static ssize_t padsp_poll(enum ossp_opcode opcode,
1129 void *carg, void *din, size_t din_sz,
1130 void *rarg, void *dout, size_t *dout_szp, int tfd)
1132 unsigned revents = 0;
1134 if (prepare_streams() < 0)
1137 stream_notify |= *(int *)carg;
1140 pa_stream_writable_size(stream[PLAY]) >= user_frag_size)
1143 pa_stream_readable_size(stream[REC]) >= user_frag_size)
1146 *(unsigned *)rarg = revents;
1150 static ssize_t padsp_mmap(enum ossp_opcode opcode,
1151 void *carg, void *din, size_t din_sz,
1152 void *rarg, void *dout, size_t *dout_szp, int tfd)
1154 struct ossp_dsp_mmap_arg *arg = carg;
1157 assert(!mmap_map[dir]);
1161 /* arg->size is rounded up to the nearest page boundary.
1162 * There is no way to tell what the actual requested value is
1163 * but assume that it was the reported buffer space if it
1164 * falls into the same page aligned range.
1166 mmap_raw_size = arg->size;
1167 if (user_max_length && user_max_length < mmap_raw_size &&
1168 round_up(mmap_raw_size, page_size) ==
1169 round_up(user_max_length, page_size)) {
1170 info("MMAP adjusting raw_size %zu -> %zu",
1171 mmap_raw_size, user_max_length);
1172 mmap_raw_size = user_max_length;
1175 dbg0("MMAP server-addr=%p sz=%zu", ossp_mmap_addr[dir], mmap_raw_size);
1177 mmap_map[dir] = ossp_mmap_addr[dir];
1179 /* if mmapped, only mmapped streams are enabled */
1180 stream_enabled[PLAY] = !!mmap_map[PLAY];
1181 stream_enabled[REC] = !!mmap_map[REC];
1186 static ssize_t padsp_munmap(enum ossp_opcode opcode,
1187 void *carg, void *din, size_t din_sz,
1188 void *rarg, void *dout, size_t *dout_szp, int tfd)
1190 int dir = *(int *)carg;
1192 assert(mmap_map[dir]);
1194 mmap_map[dir] = NULL;
1198 static ssize_t padsp_flush(enum ossp_opcode opcode,
1199 void *carg, void *din, size_t din_sz,
1200 void *rarg, void *dout, size_t *dout_szp, int tfd)
1202 flush_streams(opcode == OSSP_DSP_SYNC);
1206 static ssize_t padsp_post(enum ossp_opcode opcode,
1207 void *carg, void *din, size_t din_sz,
1208 void *rarg, void *dout, size_t *dout_szp, int tfd)
1210 return trigger_streams(1, -1);
1213 static ssize_t padsp_get_param(enum ossp_opcode opcode,
1214 void *carg, void *din, size_t din_sz,
1215 void *rarg, void *dout, size_t *dout_szp,
1221 case OSSP_DSP_GET_RATE:
1222 v = sample_spec.rate;
1225 case OSSP_DSP_GET_CHANNELS:
1226 v = sample_spec.channels;
1229 case OSSP_DSP_GET_FORMAT:
1230 v = fmt_pa_to_oss(sample_spec.format);
1233 case OSSP_DSP_GET_BLKSIZE:
1234 if (prepare_streams() < 0)
1239 case OSSP_DSP_GET_FORMATS:
1240 v = AFMT_U8 | AFMT_A_LAW | AFMT_MU_LAW | AFMT_S16_LE |
1241 AFMT_S16_BE | AFMT_FLOAT | AFMT_S32_LE | AFMT_S32_BE;
1244 case OSSP_DSP_GET_TRIGGER:
1245 if (!stream_corked[PLAY])
1246 v |= PCM_ENABLE_OUTPUT;
1247 if (!stream_corked[REC])
1248 v |= PCM_ENABLE_INPUT;
1260 static ssize_t padsp_set_param(enum ossp_opcode opcode,
1261 void *carg, void *din, size_t din_sz,
1262 void *rarg, void *dout, size_t *dout_szp,
1265 pa_sample_spec new_spec = sample_spec;
1266 int v = *(int *)carg;
1268 /* kill the streams before changing parameters */
1272 case OSSP_DSP_SET_RATE:
1274 if (pa_sample_spec_valid(&new_spec))
1275 sample_spec = new_spec;
1276 v = sample_spec.rate;
1279 case OSSP_DSP_SET_CHANNELS:
1280 new_spec.channels = v;
1281 if (pa_sample_spec_valid(&new_spec))
1282 sample_spec = new_spec;
1283 v = sample_spec.channels;
1286 case OSSP_DSP_SET_FORMAT:
1287 new_spec.format = fmt_oss_to_pa(v);
1288 if (pa_sample_spec_valid(&new_spec))
1289 sample_spec = new_spec;
1290 v = fmt_pa_to_oss(sample_spec.format);
1293 case OSSP_DSP_SET_SUBDIVISION:
1295 v = user_subdivision ?: 1;
1299 user_subdivision = v;
1302 case OSSP_DSP_SET_FRAGMENT:
1303 user_subdivision = 0;
1304 user_frag_size = 1 << (v & 0xffff);
1305 user_max_frags = (v >> 16) & 0xffff;
1306 if (user_frag_size < 4)
1308 if (user_max_frags < 2)
1320 static ssize_t padsp_set_trigger(enum ossp_opcode opcode,
1321 void *carg, void *din, size_t din_sz,
1322 void *rarg, void *dout, size_t *dout_szp,
1325 int enable = *(int *)carg;
1327 return trigger_streams(enable & PCM_ENABLE_OUTPUT,
1328 enable & PCM_ENABLE_INPUT);
1331 static ssize_t padsp_get_space(enum ossp_opcode opcode,
1332 void *carg, void *din, size_t din_sz,
1333 void *rarg, void *dout, size_t *dout_szp, int tfd)
1335 int dir = (opcode == OSSP_DSP_GET_OSPACE) ? PLAY : REC;
1336 struct audio_buf_info info = { };
1339 rc = prepare_streams();
1344 info.fragments = mmap_raw_size / user_frag_size;
1345 info.fragstotal = info.fragments;
1346 info.fragsize = user_frag_size;
1347 info.bytes = mmap_raw_size;
1352 space = pa_stream_writable_size(stream[PLAY]);
1354 space = pa_stream_readable_size(stream[REC]);
1356 space = round_down(space, user_frag_size);
1357 space = min(space, user_frag_size * user_max_frags);
1359 info.fragments = space / user_frag_size;
1360 info.fragstotal = user_max_frags;
1361 info.fragsize = user_frag_size;
1365 *(struct audio_buf_info *)rarg = info;
1369 static ssize_t padsp_get_ptr(enum ossp_opcode opcode,
1370 void *carg, void *din, size_t din_sz,
1371 void *rarg, void *dout, size_t *dout_szp, int tfd)
1373 int dir = (opcode == OSSP_DSP_GET_OPTR) ? PLAY : REC;
1374 struct count_info info = { };
1376 if (prepare_streams() < 0 || !stream[dir])
1379 if (mmap_map[dir]) {
1380 /* mmap operation in progress, report mmap buffer parameters */
1384 mmap_consume_rstg();
1386 info.bytes = mmap_idx[dir];
1387 info.blocks = (mmap_idx[dir] - mmap_last_idx[dir]) / frame_size;
1388 info.ptr = mmap_idx[dir] % mmap_size;
1390 mmap_last_idx[dir] = mmap_idx[dir];
1392 /* simulate pointers using timestamps */
1393 double bpus = (double)sample_bps / 1000000;
1394 size_t bytes, delta_bytes;
1395 pa_usec_t usec, delta;
1397 if (pa_stream_get_time(stream[dir], &usec) < 0) {
1398 warn_pa("pa_stream_get_time() failed");
1402 delta = usec - stream_ptr_timestamp[dir];
1403 stream_ptr_timestamp[dir] = usec;
1404 bytes = bpus * usec;
1405 delta_bytes = bpus * delta;
1407 info.bytes = bytes & INT_MAX;
1408 info.blocks = (delta_bytes + frame_size - 1) / frame_size;
1409 info.ptr = bytes % user_max_length;
1412 *(struct count_info *)rarg = info;
1416 static ssize_t padsp_get_odelay(enum ossp_opcode opcode,
1417 void *carg, void *din, size_t din_sz,
1418 void *rarg, void *dout, size_t *dout_szp,
1421 double bpus = (double)sample_bps / 1000000;
1424 if (prepare_streams() < 0 || !stream[PLAY])
1427 if (pa_stream_get_latency(stream[PLAY], &usec, NULL) < 0) {
1428 warn_pa("pa_stream_get_latency() failed");
1432 *(int *)rarg = bpus * usec;
1436 static ossp_action_fn_t action_fn_tbl[OSSP_NR_OPCODES] = {
1437 [OSSP_MIXER] = padsp_mixer,
1438 [OSSP_DSP_OPEN] = padsp_open,
1439 [OSSP_DSP_READ] = padsp_read,
1440 [OSSP_DSP_WRITE] = padsp_write,
1441 [OSSP_DSP_POLL] = padsp_poll,
1442 [OSSP_DSP_MMAP] = padsp_mmap,
1443 [OSSP_DSP_MUNMAP] = padsp_munmap,
1444 [OSSP_DSP_RESET] = padsp_flush,
1445 [OSSP_DSP_SYNC] = padsp_flush,
1446 [OSSP_DSP_POST] = padsp_post,
1447 [OSSP_DSP_GET_RATE] = padsp_get_param,
1448 [OSSP_DSP_GET_CHANNELS] = padsp_get_param,
1449 [OSSP_DSP_GET_FORMAT] = padsp_get_param,
1450 [OSSP_DSP_GET_BLKSIZE] = padsp_get_param,
1451 [OSSP_DSP_GET_FORMATS] = padsp_get_param,
1452 [OSSP_DSP_SET_RATE] = padsp_set_param,
1453 [OSSP_DSP_SET_CHANNELS] = padsp_set_param,
1454 [OSSP_DSP_SET_FORMAT] = padsp_set_param,
1455 [OSSP_DSP_SET_SUBDIVISION] = padsp_set_param,
1456 [OSSP_DSP_SET_FRAGMENT] = padsp_set_param,
1457 [OSSP_DSP_GET_TRIGGER] = padsp_get_param,
1458 [OSSP_DSP_SET_TRIGGER] = padsp_set_trigger,
1459 [OSSP_DSP_GET_OSPACE] = padsp_get_space,
1460 [OSSP_DSP_GET_ISPACE] = padsp_get_space,
1461 [OSSP_DSP_GET_OPTR] = padsp_get_ptr,
1462 [OSSP_DSP_GET_IPTR] = padsp_get_ptr,
1463 [OSSP_DSP_GET_ODELAY] = padsp_get_odelay,
1466 static int action_pre(void)
1468 pa_threaded_mainloop_lock(mainloop);
1470 pa_threaded_mainloop_unlock(mainloop);
1476 static void action_post(void)
1478 pa_threaded_mainloop_unlock(mainloop);
1481 int main(int argc, char **argv)
1485 ossp_slave_init(argc, argv);
1487 page_size = sysconf(_SC_PAGE_SIZE);
1489 mainloop = pa_threaded_mainloop_new();
1491 err("failed to allocate mainloop");
1494 mainloop_api = pa_threaded_mainloop_get_api(mainloop);
1496 if (pa_threaded_mainloop_start(mainloop)) {
1497 err("pa_mainloop_start() failed");
1501 /* Okay, now we're open for business */
1504 rc = ossp_slave_process_command(ossp_cmd_fd, action_fn_tbl,
1505 action_pre, action_post);
1506 } while (rc > 0 && !fail_code);
1510 pa_threaded_mainloop_lock(mainloop);
1514 pa_context_disconnect(context);
1515 pa_context_unref(context);
1518 pa_threaded_mainloop_unlock(mainloop);
1520 pa_threaded_mainloop_stop(mainloop);
1521 pa_threaded_mainloop_free(mainloop);
1523 return fail_code ? 1 : 0;