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 notify_mmap_fill_play(size_t mmap_size
, size_t pos
, size_t bytes
)
791 size_t count
= min(bytes
, mmap_size
- pos
);
792 struct ossp_notify event
= { .magic
= OSSP_NOTIFY_MAGIC
,
793 .opcode
= OSSP_NOTIFY_FILL
};
795 ossp_mmap_transfer
[PLAY
].pos
= pos
;
796 ossp_mmap_transfer
[PLAY
].bytes
= count
;
798 ret
= write(ossp_notify_fd
, &event
, sizeof(event
));
799 if (ret
!= sizeof(event
)) {
801 err_e(-errno
, "write to notify_fd failed");
806 sem_wait(&ossp_mmap_transfer
[PLAY
].sem
);
809 pos
= (pos
+ count
) % mmap_size
;
813 static void notify_mmap_store_rec(size_t mmap_size
, size_t pos
, size_t bytes
)
817 size_t count
= min(bytes
, mmap_size
- pos
);
818 struct ossp_notify event
= { .magic
= OSSP_NOTIFY_MAGIC
,
819 .opcode
= OSSP_NOTIFY_STORE
};
821 ossp_mmap_transfer
[REC
].pos
= pos
;
822 ossp_mmap_transfer
[REC
].bytes
= count
;
824 ret
= write(ossp_notify_fd
, &event
, sizeof(event
));
825 if (ret
!= sizeof(event
)) {
827 err_e(-errno
, "write to notify_fd failed");
832 sem_wait(&ossp_mmap_transfer
[REC
].sem
);
835 pos
= (pos
+ count
) % mmap_size
;
839 static void mmap_fill_pstg(void)
841 struct ring_buf
*stg
= &mmap_stg
[PLAY
];
842 struct ring_buf mmap
;
843 uint64_t new_idx
= get_mmap_idx(PLAY
);
844 size_t bytes
, space
, size
;
847 if (new_idx
<= mmap_idx
[PLAY
])
850 bytes
= new_idx
- mmap_idx
[PLAY
];
851 space
= ring_space(stg
);
853 if (bytes
> mmap_size
) {
854 dbg0("mmap playback transfer chunk bigger than "
855 "mmap size (bytes=%zu mmap_size=%zu)", bytes
, mmap_size
);
861 dbg0("mmap playback staging buffer overflow "
862 "(bytes=%zu space=%zu)", bytes
, space
);
867 notify_mmap_fill_play(mmap_size
, mmap_idx
[PLAY
] % mmap_size
, bytes
);
869 ring_manual_init(&mmap
, mmap_map
[PLAY
], mmap_size
,
870 new_idx
% mmap_size
, bytes
);
872 while ((data
= ring_data(&mmap
, &size
))) {
873 ring_fill(stg
, data
, size
);
874 ring_consume(&mmap
, size
);
877 mmap_idx
[PLAY
] = new_idx
;
880 static void mmap_consume_rstg(void)
882 struct ring_buf
*stg
= &mmap_stg
[REC
];
883 struct ring_buf mmap
;
884 uint64_t new_idx
= get_mmap_idx(REC
);
885 uint64_t fill_idx
= mmap_idx
[REC
];
888 if (new_idx
<= mmap_idx
[REC
])
891 space
= new_idx
- mmap_idx
[REC
]; /* mmapped space to fill in */
892 bytes
= ring_bytes(stg
); /* recorded bytes in staging */
896 dbg0("mmap recording staging buffer underflow "
897 "(space=%zu bytes=%zu)", space
, bytes
);
901 if (space
> mmap_size
) {
903 dbg0("mmap recording transfer chunk bigger than "
904 "mmap size (space=%zu mmap_size=%zu)",
910 /* If resync is requested, leave lead bytes in the staging
911 * buffer and copy everything else such that data is filled
912 * upto the new_idx. If there are more bytes in staging than
913 * available space, those will be dropped.
915 if (mmap_sync
[REC
]) {
916 ssize_t avail
= bytes
- mmap_lead
[REC
];
918 /* make sure we always have lead bytes in staging */
923 dbg0("dropping %zu bytes from record staging buffer",
925 ring_consume(&mmap_stg
[REC
], avail
- space
);
928 dbg0("skippping %zu bytes in record mmap map",
933 assert(new_idx
>= avail
);
934 fill_idx
= new_idx
- avail
;
938 ring_manual_init(&mmap
, mmap_map
[REC
], mmap_size
,
939 fill_idx
% mmap_size
, 0);
945 data
= ring_data(stg
, &size
);
948 todo
= min(size
, space
);
949 ring_fill(&mmap
, data
, todo
);
951 ring_consume(stg
, todo
);
955 notify_mmap_store_rec(mmap_size
, fill_idx
% mmap_size
, ring_bytes(&mmap
));
958 mmap_idx
[REC
] = new_idx
;
961 static void do_mmap_write(size_t space
)
963 struct ring_buf
*stg
= &mmap_stg
[PLAY
];
967 space
= round_down(space
, frame_size
);
970 while (space
&& (data
= ring_data(stg
, &todo
))) {
971 pa_seek_mode_t mode
= PA_SEEK_RELATIVE_END
;
974 todo
= min(todo
, space
);
976 if (mmap_sync
[PLAY
]) {
977 mode
= PA_SEEK_RELATIVE_ON_READ
;
978 offset
= (int64_t)mmap_lead
[PLAY
] - ring_bytes(stg
);
979 dbg0("mmap resync, offset=%ld", (long)offset
);
982 if (pa_stream_write(stream
[PLAY
], data
, todo
, NULL
,
984 err_pa("pa_stream_write() failed");
990 ring_consume(stg
, todo
);
995 static void do_mmap_read(size_t bytes
)
997 struct ring_buf
*stg
= &mmap_stg
[REC
];
999 bytes
= round_down(bytes
, frame_size
);
1000 mmap_consume_rstg();
1003 const void *peek_data
;
1006 if (pa_stream_peek(stream
[REC
], &peek_data
, &size
)) {
1007 err_pa("pa_stream_peek() failed");
1015 if (size
<= ring_space(stg
))
1016 ring_fill(stg
, peek_data
, size
);
1018 if (!mmap_sync
[REC
])
1019 dbg0("recording staging buffer overflow, "
1020 "requesting resync");
1024 pa_stream_drop(stream
[REC
]);
1029 static void stream_rw_callback(pa_stream
*s
, size_t length
, void *userdata
)
1033 if (s
== stream
[PLAY
]) {
1034 size
= pa_stream_writable_size(s
);
1036 do_mmap_write(size
);
1037 } else if (s
== stream
[REC
]) {
1038 size
= pa_stream_readable_size(s
);
1042 dbg0("stream_rw_callback(): unknown stream %p PLAY/REC=%p/%p\n",
1043 s
, stream
[PLAY
], stream
[REC
]);
1047 if (size
< user_frag_size
)
1050 pa_threaded_mainloop_signal(mainloop
, 0);
1051 if (stream_notify
) {
1052 struct ossp_notify event
= { .magic
= OSSP_NOTIFY_MAGIC
,
1053 .opcode
= OSSP_NOTIFY_POLL
};
1056 ret
= write(ossp_notify_fd
, &event
, sizeof(event
));
1057 if (ret
!= sizeof(event
)) {
1059 err_e(-errno
, "write to notify_fd failed");
1061 /* This function is run from PA mainloop and
1062 * thus the following padsp_done() won't be
1063 * noticed before the mainthread tries to run
1064 * the next command. Well, that's good enough.
1072 static ssize_t
padsp_write(enum ossp_opcode opcode
,
1073 void *carg
, void *din
, size_t din_sz
,
1074 void *rarg
, void *dout
, size_t *dout_szp
, int tfd
)
1076 struct ossp_dsp_rw_arg
*arg
= carg
;
1079 if (prepare_streams() || !stream
[PLAY
])
1084 size
= pa_stream_writable_size(stream
[PLAY
]);
1085 if (arg
->nonblock
|| size
>= user_frag_size
)
1087 pa_threaded_mainloop_wait(mainloop
);
1091 size
= round_down(size
, user_frag_size
);
1095 size
= min(size
, din_sz
);
1097 if (pa_stream_write(stream
[PLAY
], din
, size
, NULL
,
1098 0, PA_SEEK_RELATIVE
) < 0) {
1099 err_pa("pa_stream_write() failed");
1100 return padsp_done();
1106 static ssize_t
padsp_read(enum ossp_opcode opcode
,
1107 void *carg
, void *din
, size_t din_sz
,
1108 void *rarg
, void *dout
, size_t *dout_szp
, int tfd
)
1110 struct ossp_dsp_rw_arg
*arg
= carg
;
1114 if (prepare_streams() || !stream
[REC
])
1117 if (!arg
->nonblock
) {
1120 size
= pa_stream_readable_size(stream
[REC
]);
1121 if (size
+ ring_bytes(&rec_buf
) >= user_frag_size
)
1123 pa_threaded_mainloop_wait(mainloop
);
1128 while (ring_bytes(&rec_buf
) < max(user_frag_size
, *dout_szp
)) {
1129 const void *peek_data
;
1131 if (pa_stream_peek(stream
[REC
], &peek_data
, &size
) < 0) {
1132 err_pa("pa_stream_peek() failed");
1133 return padsp_done();
1139 if (ring_space(&rec_buf
) < size
) {
1142 bufsz
= ring_size(&rec_buf
);
1143 bufsz
= max(2 * bufsz
, bufsz
+ 2 * size
);
1145 if (ring_resize(&rec_buf
, bufsz
)) {
1146 err("failed to allocate recording buffer");
1147 return padsp_done();
1151 ring_fill(&rec_buf
, peek_data
, size
);
1152 pa_stream_drop(stream
[REC
]);
1155 size
= round_down(ring_bytes(&rec_buf
), user_frag_size
);
1163 *dout_szp
= size
= min(size
, *dout_szp
);
1168 data
= ring_data(&rec_buf
, &cnt
);
1171 cnt
= min(size
, cnt
);
1172 memcpy(dout
, data
, cnt
);
1173 ring_consume(&rec_buf
, cnt
);
1181 static ssize_t
padsp_poll(enum ossp_opcode opcode
,
1182 void *carg
, void *din
, size_t din_sz
,
1183 void *rarg
, void *dout
, size_t *dout_szp
, int tfd
)
1185 unsigned revents
= 0;
1187 if (prepare_streams() < 0)
1190 stream_notify
|= *(int *)carg
;
1193 pa_stream_writable_size(stream
[PLAY
]) >= user_frag_size
)
1196 pa_stream_readable_size(stream
[REC
]) >= user_frag_size
)
1199 *(unsigned *)rarg
= revents
;
1203 static ssize_t
padsp_mmap(enum ossp_opcode opcode
,
1204 void *carg
, void *din
, size_t din_sz
,
1205 void *rarg
, void *dout
, size_t *dout_szp
, int tfd
)
1207 struct ossp_dsp_mmap_arg
*arg
= carg
;
1210 assert(!mmap_map
[dir
]);
1214 /* arg->size is rounded up to the nearest page boundary.
1215 * There is no way to tell what the actual requested value is
1216 * but assume that it was the reported buffer space if it
1217 * falls into the same page aligned range.
1219 mmap_raw_size
= arg
->size
;
1220 if (user_max_length
&& user_max_length
< mmap_raw_size
&&
1221 round_up(mmap_raw_size
, page_size
) ==
1222 round_up(user_max_length
, page_size
)) {
1223 info("MMAP adjusting raw_size %zu -> %zu",
1224 mmap_raw_size
, user_max_length
);
1225 mmap_raw_size
= user_max_length
;
1228 dbg0("MMAP server-addr=%p sz=%zu", ossp_mmap_addr
[dir
], mmap_raw_size
);
1230 mmap_map
[dir
] = ossp_mmap_addr
[dir
];
1232 /* if mmapped, only mmapped streams are enabled */
1233 stream_enabled
[PLAY
] = !!mmap_map
[PLAY
];
1234 stream_enabled
[REC
] = !!mmap_map
[REC
];
1239 static ssize_t
padsp_munmap(enum ossp_opcode opcode
,
1240 void *carg
, void *din
, size_t din_sz
,
1241 void *rarg
, void *dout
, size_t *dout_szp
, int tfd
)
1243 int dir
= *(int *)carg
;
1245 assert(mmap_map
[dir
]);
1247 mmap_map
[dir
] = NULL
;
1251 static ssize_t
padsp_flush(enum ossp_opcode opcode
,
1252 void *carg
, void *din
, size_t din_sz
,
1253 void *rarg
, void *dout
, size_t *dout_szp
, int tfd
)
1255 flush_streams(opcode
== OSSP_DSP_SYNC
);
1259 static ssize_t
padsp_post(enum ossp_opcode opcode
,
1260 void *carg
, void *din
, size_t din_sz
,
1261 void *rarg
, void *dout
, size_t *dout_szp
, int tfd
)
1263 return trigger_streams(1, -1);
1266 static ssize_t
padsp_get_param(enum ossp_opcode opcode
,
1267 void *carg
, void *din
, size_t din_sz
,
1268 void *rarg
, void *dout
, size_t *dout_szp
,
1274 case OSSP_DSP_GET_RATE
:
1275 v
= sample_spec
.rate
;
1278 case OSSP_DSP_GET_CHANNELS
:
1279 v
= sample_spec
.channels
;
1282 case OSSP_DSP_GET_FORMAT
:
1283 v
= fmt_pa_to_oss(sample_spec
.format
);
1286 case OSSP_DSP_GET_BLKSIZE
:
1287 if (prepare_streams() < 0)
1292 case OSSP_DSP_GET_FORMATS
:
1293 v
= AFMT_U8
| AFMT_A_LAW
| AFMT_MU_LAW
| AFMT_S16_LE
|
1294 AFMT_S16_BE
| AFMT_FLOAT
| AFMT_S32_LE
| AFMT_S32_BE
;
1297 case OSSP_DSP_GET_TRIGGER
:
1298 if (!stream_corked
[PLAY
])
1299 v
|= PCM_ENABLE_OUTPUT
;
1300 if (!stream_corked
[REC
])
1301 v
|= PCM_ENABLE_INPUT
;
1313 static ssize_t
padsp_set_param(enum ossp_opcode opcode
,
1314 void *carg
, void *din
, size_t din_sz
,
1315 void *rarg
, void *dout
, size_t *dout_szp
,
1318 pa_sample_spec new_spec
= sample_spec
;
1319 int v
= *(int *)carg
;
1321 /* kill the streams before changing parameters */
1325 case OSSP_DSP_SET_RATE
:
1327 if (pa_sample_spec_valid(&new_spec
))
1328 sample_spec
= new_spec
;
1329 v
= sample_spec
.rate
;
1332 case OSSP_DSP_SET_CHANNELS
:
1333 new_spec
.channels
= v
;
1334 if (pa_sample_spec_valid(&new_spec
))
1335 sample_spec
= new_spec
;
1336 v
= sample_spec
.channels
;
1339 case OSSP_DSP_SET_FORMAT
:
1340 new_spec
.format
= fmt_oss_to_pa(v
);
1341 if (pa_sample_spec_valid(&new_spec
))
1342 sample_spec
= new_spec
;
1343 v
= fmt_pa_to_oss(sample_spec
.format
);
1346 case OSSP_DSP_SET_SUBDIVISION
:
1348 v
= user_subdivision
?: 1;
1352 user_subdivision
= v
;
1355 case OSSP_DSP_SET_FRAGMENT
:
1356 user_subdivision
= 0;
1357 user_frag_size
= 1 << (v
& 0xffff);
1358 user_max_frags
= (v
>> 16) & 0xffff;
1359 if (user_frag_size
< 4)
1361 if (user_max_frags
< 2)
1373 static ssize_t
padsp_set_trigger(enum ossp_opcode opcode
,
1374 void *carg
, void *din
, size_t din_sz
,
1375 void *rarg
, void *dout
, size_t *dout_szp
,
1378 int enable
= *(int *)carg
;
1380 return trigger_streams(enable
& PCM_ENABLE_OUTPUT
,
1381 enable
& PCM_ENABLE_INPUT
);
1384 static ssize_t
padsp_get_space(enum ossp_opcode opcode
,
1385 void *carg
, void *din
, size_t din_sz
,
1386 void *rarg
, void *dout
, size_t *dout_szp
, int tfd
)
1388 int dir
= (opcode
== OSSP_DSP_GET_OSPACE
) ? PLAY
: REC
;
1389 struct audio_buf_info info
= { };
1392 rc
= prepare_streams();
1397 info
.fragments
= mmap_raw_size
/ user_frag_size
;
1398 info
.fragstotal
= info
.fragments
;
1399 info
.fragsize
= user_frag_size
;
1400 info
.bytes
= mmap_raw_size
;
1405 space
= pa_stream_writable_size(stream
[PLAY
]);
1407 space
= pa_stream_readable_size(stream
[REC
]);
1409 space
= round_down(space
, user_frag_size
);
1410 space
= min(space
, user_frag_size
* user_max_frags
);
1412 info
.fragments
= space
/ user_frag_size
;
1413 info
.fragstotal
= user_max_frags
;
1414 info
.fragsize
= user_frag_size
;
1418 *(struct audio_buf_info
*)rarg
= info
;
1422 static ssize_t
padsp_get_ptr(enum ossp_opcode opcode
,
1423 void *carg
, void *din
, size_t din_sz
,
1424 void *rarg
, void *dout
, size_t *dout_szp
, int tfd
)
1426 int dir
= (opcode
== OSSP_DSP_GET_OPTR
) ? PLAY
: REC
;
1427 struct count_info info
= { };
1429 if (prepare_streams() < 0 || !stream
[dir
])
1432 if (mmap_map
[dir
]) {
1433 /* mmap operation in progress, report mmap buffer parameters */
1437 mmap_consume_rstg();
1439 info
.bytes
= mmap_idx
[dir
];
1440 info
.blocks
= (mmap_idx
[dir
] - mmap_last_idx
[dir
]) / frame_size
;
1441 info
.ptr
= mmap_idx
[dir
] % mmap_size
;
1443 mmap_last_idx
[dir
] = mmap_idx
[dir
];
1445 /* simulate pointers using timestamps */
1446 double bpus
= (double)sample_bps
/ 1000000;
1447 size_t bytes
, delta_bytes
;
1448 pa_usec_t usec
, delta
;
1450 if (pa_stream_get_time(stream
[dir
], &usec
) < 0) {
1451 warn_pa("pa_stream_get_time() failed");
1455 delta
= usec
- stream_ptr_timestamp
[dir
];
1456 stream_ptr_timestamp
[dir
] = usec
;
1457 bytes
= bpus
* usec
;
1458 delta_bytes
= bpus
* delta
;
1460 info
.bytes
= bytes
& INT_MAX
;
1461 info
.blocks
= (delta_bytes
+ frame_size
- 1) / frame_size
;
1462 info
.ptr
= bytes
% user_max_length
;
1465 *(struct count_info
*)rarg
= info
;
1469 static ssize_t
padsp_get_odelay(enum ossp_opcode opcode
,
1470 void *carg
, void *din
, size_t din_sz
,
1471 void *rarg
, void *dout
, size_t *dout_szp
,
1474 double bpus
= (double)sample_bps
/ 1000000;
1477 if (prepare_streams() < 0 || !stream
[PLAY
])
1480 if (pa_stream_get_latency(stream
[PLAY
], &usec
, NULL
) < 0) {
1481 warn_pa("pa_stream_get_latency() failed");
1485 *(int *)rarg
= bpus
* usec
;
1489 static ossp_action_fn_t action_fn_tbl
[OSSP_NR_OPCODES
] = {
1490 [OSSP_MIXER
] = padsp_mixer
,
1491 [OSSP_DSP_OPEN
] = padsp_open
,
1492 [OSSP_DSP_READ
] = padsp_read
,
1493 [OSSP_DSP_WRITE
] = padsp_write
,
1494 [OSSP_DSP_POLL
] = padsp_poll
,
1495 [OSSP_DSP_MMAP
] = padsp_mmap
,
1496 [OSSP_DSP_MUNMAP
] = padsp_munmap
,
1497 [OSSP_DSP_RESET
] = padsp_flush
,
1498 [OSSP_DSP_SYNC
] = padsp_flush
,
1499 [OSSP_DSP_POST
] = padsp_post
,
1500 [OSSP_DSP_GET_RATE
] = padsp_get_param
,
1501 [OSSP_DSP_GET_CHANNELS
] = padsp_get_param
,
1502 [OSSP_DSP_GET_FORMAT
] = padsp_get_param
,
1503 [OSSP_DSP_GET_BLKSIZE
] = padsp_get_param
,
1504 [OSSP_DSP_GET_FORMATS
] = padsp_get_param
,
1505 [OSSP_DSP_SET_RATE
] = padsp_set_param
,
1506 [OSSP_DSP_SET_CHANNELS
] = padsp_set_param
,
1507 [OSSP_DSP_SET_FORMAT
] = padsp_set_param
,
1508 [OSSP_DSP_SET_SUBDIVISION
] = padsp_set_param
,
1509 [OSSP_DSP_SET_FRAGMENT
] = padsp_set_param
,
1510 [OSSP_DSP_GET_TRIGGER
] = padsp_get_param
,
1511 [OSSP_DSP_SET_TRIGGER
] = padsp_set_trigger
,
1512 [OSSP_DSP_GET_OSPACE
] = padsp_get_space
,
1513 [OSSP_DSP_GET_ISPACE
] = padsp_get_space
,
1514 [OSSP_DSP_GET_OPTR
] = padsp_get_ptr
,
1515 [OSSP_DSP_GET_IPTR
] = padsp_get_ptr
,
1516 [OSSP_DSP_GET_ODELAY
] = padsp_get_odelay
,
1519 static int action_pre(void)
1521 pa_threaded_mainloop_lock(mainloop
);
1523 pa_threaded_mainloop_unlock(mainloop
);
1529 static void action_post(void)
1531 pa_threaded_mainloop_unlock(mainloop
);
1534 int main(int argc
, char **argv
)
1538 ossp_slave_init(argc
, argv
);
1540 page_size
= sysconf(_SC_PAGE_SIZE
);
1542 mainloop
= pa_threaded_mainloop_new();
1544 err("failed to allocate mainloop");
1547 mainloop_api
= pa_threaded_mainloop_get_api(mainloop
);
1549 if (pa_threaded_mainloop_start(mainloop
)) {
1550 err("pa_mainloop_start() failed");
1554 /* Okay, now we're open for business */
1557 rc
= ossp_slave_process_command(ossp_cmd_fd
, action_fn_tbl
,
1558 action_pre
, action_post
);
1559 } while (rc
> 0 && !fail_code
);
1563 pa_threaded_mainloop_lock(mainloop
);
1567 pa_context_disconnect(context
);
1568 pa_context_unref(context
);
1571 pa_threaded_mainloop_unlock(mainloop
);
1573 pa_threaded_mainloop_stop(mainloop
);
1574 pa_threaded_mainloop_free(mainloop
);
1576 return fail_code
? 1 : 0;