4 * \brief PCM Direct Stream Mixing (dmix) Plugin Interface
5 * \author Jaroslav Kysela <perex@perex.cz>
9 * PCM - Direct Stream Mixing
10 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
13 * This library is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU Lesser General Public License as
15 * published by the Free Software Foundation; either version 2.1 of
16 * the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
38 #include <sys/ioctl.h>
43 #include <sys/socket.h>
46 #include "pcm_direct.h"
49 /* entry for static linking */
50 const char *_snd_module_pcm_dmix = "";
54 /* start is pending - this state happens when rate plugin does a delayed commit */
55 #define STATE_RUN_PENDING 1024
62 static int shm_sum_discard(snd_pcm_direct_t *dmix);
65 * sum ring buffer shared memory area
67 static int shm_sum_create_or_connect(snd_pcm_direct_t *dmix)
73 size = dmix->shmptr->s.channels *
74 dmix->shmptr->s.buffer_size *
77 dmix->u.dmix.shmid_sum = shmget(dmix->ipc_key + 1, size,
78 IPC_CREAT | dmix->ipc_perm);
80 if (dmix->u.dmix.shmid_sum < 0) {
82 if ((tmpid = shmget(dmix->ipc_key + 1, 0, dmix->ipc_perm)) != -1)
83 if (!shmctl(tmpid, IPC_STAT, &buf))
85 /* no users so destroy the segment */
86 if (!shmctl(tmpid, IPC_RMID, NULL))
90 if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0) {
92 shm_sum_discard(dmix);
95 if (dmix->ipc_gid >= 0) {
96 buf.shm_perm.gid = dmix->ipc_gid;
97 shmctl(dmix->u.dmix.shmid_sum, IPC_SET, &buf);
99 dmix->u.dmix.sum_buffer = shmat(dmix->u.dmix.shmid_sum, 0, 0);
100 if (dmix->u.dmix.sum_buffer == (void *) -1) {
102 shm_sum_discard(dmix);
105 mlock(dmix->u.dmix.sum_buffer, size);
109 static int shm_sum_discard(snd_pcm_direct_t *dmix)
114 if (dmix->u.dmix.shmid_sum < 0)
116 if (dmix->u.dmix.sum_buffer != (void *) -1 && shmdt(dmix->u.dmix.sum_buffer) < 0)
118 dmix->u.dmix.sum_buffer = (void *) -1;
119 if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0)
121 if (buf.shm_nattch == 0) { /* we're the last user, destroy the segment */
122 if (shmctl(dmix->u.dmix.shmid_sum, IPC_RMID, NULL) < 0)
126 dmix->u.dmix.shmid_sum = -1;
130 static void dmix_server_free(snd_pcm_direct_t *dmix)
132 /* remove the memory region */
133 shm_sum_create_or_connect(dmix);
134 shm_sum_discard(dmix);
138 * the main function of this plugin: mixing
139 * FIXME: optimize it for different architectures
142 #include "pcm_dmix_generic.c"
143 #if defined(__i386__)
144 #include "pcm_dmix_i386.c"
145 #elif defined(__x86_64__)
146 #include "pcm_dmix_x86_64.c"
149 #define mix_select_callbacks(x) generic_mix_select_callbacks(x)
150 #define dmix_supported_format generic_dmix_supported_format
154 static void mix_areas(snd_pcm_direct_t *dmix,
155 const snd_pcm_channel_area_t *src_areas,
156 const snd_pcm_channel_area_t *dst_areas,
157 snd_pcm_uframes_t src_ofs,
158 snd_pcm_uframes_t dst_ofs,
159 snd_pcm_uframes_t size)
161 unsigned int src_step, dst_step;
162 unsigned int chn, dchn, channels, sample_size;
163 mix_areas_t *do_mix_areas;
165 channels = dmix->channels;
166 switch (dmix->shmptr->s.format) {
167 case SND_PCM_FORMAT_S16_LE:
168 case SND_PCM_FORMAT_S16_BE:
170 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_16;
172 case SND_PCM_FORMAT_S32_LE:
173 case SND_PCM_FORMAT_S32_BE:
175 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_32;
177 case SND_PCM_FORMAT_S24_LE:
179 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_24;
181 case SND_PCM_FORMAT_S24_3LE:
183 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_24;
185 case SND_PCM_FORMAT_U8:
187 do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_u8;
192 if (dmix->interleaved) {
194 * process all areas in one loop
195 * it optimizes the memory accesses for this case
197 do_mix_areas(size * channels,
198 (unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels,
199 (unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels,
200 dmix->u.dmix.sum_buffer + dst_ofs * channels,
206 for (chn = 0; chn < channels; chn++) {
207 dchn = dmix->bindings ? dmix->bindings[chn] : chn;
208 if (dchn >= dmix->shmptr->s.channels)
210 src_step = src_areas[chn].step / 8;
211 dst_step = dst_areas[dchn].step / 8;
213 ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step,
214 ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step,
215 dmix->u.dmix.sum_buffer + channels * dst_ofs + chn,
218 channels * sizeof(signed int));
222 static void remix_areas(snd_pcm_direct_t *dmix,
223 const snd_pcm_channel_area_t *src_areas,
224 const snd_pcm_channel_area_t *dst_areas,
225 snd_pcm_uframes_t src_ofs,
226 snd_pcm_uframes_t dst_ofs,
227 snd_pcm_uframes_t size)
229 unsigned int src_step, dst_step;
230 unsigned int chn, dchn, channels, sample_size;
231 mix_areas_t *do_remix_areas;
233 channels = dmix->channels;
234 switch (dmix->shmptr->s.format) {
235 case SND_PCM_FORMAT_S16_LE:
236 case SND_PCM_FORMAT_S16_BE:
238 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_16;
240 case SND_PCM_FORMAT_S32_LE:
241 case SND_PCM_FORMAT_S32_BE:
243 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_32;
245 case SND_PCM_FORMAT_S24_LE:
247 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_24;
249 case SND_PCM_FORMAT_S24_3LE:
251 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_24;
253 case SND_PCM_FORMAT_U8:
255 do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_u8;
260 if (dmix->interleaved) {
262 * process all areas in one loop
263 * it optimizes the memory accesses for this case
265 do_remix_areas(size * channels,
266 (unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels,
267 (unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels,
268 dmix->u.dmix.sum_buffer + dst_ofs * channels,
274 for (chn = 0; chn < channels; chn++) {
275 dchn = dmix->bindings ? dmix->bindings[chn] : chn;
276 if (dchn >= dmix->shmptr->s.channels)
278 src_step = src_areas[chn].step / 8;
279 dst_step = dst_areas[dchn].step / 8;
281 ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step,
282 ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step,
283 dmix->u.dmix.sum_buffer + channels * dst_ofs + chn,
286 channels * sizeof(signed int));
291 * if no concurrent access is allowed in the mixing routines, we need to protect
292 * the area via semaphore
295 #ifdef NO_CONCURRENT_ACCESS
296 #define dmix_down_sem(dmix) snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT)
297 #define dmix_up_sem(dmix) snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT)
299 #define dmix_down_sem(dmix)
300 #define dmix_up_sem(dmix)
305 * synchronize shm ring buffer with hardware
307 static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm)
309 snd_pcm_direct_t *dmix = pcm->private_data;
310 snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size;
311 snd_pcm_uframes_t appl_ptr, size, transfer;
312 const snd_pcm_channel_area_t *src_areas, *dst_areas;
314 /* calculate the size to transfer */
315 /* check the available size in the local buffer
316 * last_appl_ptr keeps the last updated position
318 size = dmix->appl_ptr - dmix->last_appl_ptr;
321 if (size >= pcm->boundary / 2)
322 size = pcm->boundary - size;
324 /* the slave_app_ptr can be far behind the slave_hw_ptr */
325 /* reduce mixing and errors here - just skip not catched writes */
326 if (dmix->slave_hw_ptr <= dmix->slave_appl_ptr)
327 slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr;
329 slave_size = dmix->slave_appl_ptr + (dmix->slave_boundary - dmix->slave_hw_ptr);
330 if (slave_size > dmix->slave_buffer_size) {
331 transfer = dmix->slave_buffer_size - slave_size;
334 dmix->last_appl_ptr += transfer;
335 dmix->last_appl_ptr %= pcm->boundary;
336 dmix->slave_appl_ptr += transfer;
337 dmix->slave_appl_ptr %= dmix->slave_boundary;
338 size = dmix->appl_ptr - dmix->last_appl_ptr;
341 if (size >= pcm->boundary / 2)
342 size = pcm->boundary - size;
345 /* check the available size in the slave PCM buffer */
346 slave_hw_ptr = dmix->slave_hw_ptr;
347 /* don't write on the last active period - this area may be cleared
348 * by the driver during mix operation...
350 slave_hw_ptr -= slave_hw_ptr % dmix->slave_period_size;
351 slave_hw_ptr += dmix->slave_buffer_size;
352 if (slave_hw_ptr >= dmix->slave_boundary)
353 slave_hw_ptr -= dmix->slave_boundary;
354 if (slave_hw_ptr < dmix->slave_appl_ptr)
355 slave_size = slave_hw_ptr + (dmix->slave_boundary - dmix->slave_appl_ptr);
357 slave_size = slave_hw_ptr - dmix->slave_appl_ptr;
358 if (slave_size < size)
363 /* add sample areas here */
364 src_areas = snd_pcm_mmap_areas(pcm);
365 dst_areas = snd_pcm_mmap_areas(dmix->spcm);
366 appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
367 dmix->last_appl_ptr += size;
368 dmix->last_appl_ptr %= pcm->boundary;
369 slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
370 dmix->slave_appl_ptr += size;
371 dmix->slave_appl_ptr %= dmix->slave_boundary;
375 if (appl_ptr + transfer > pcm->buffer_size)
376 transfer = pcm->buffer_size - appl_ptr;
377 if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
378 transfer = dmix->slave_buffer_size - slave_appl_ptr;
379 mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
383 slave_appl_ptr += transfer;
384 slave_appl_ptr %= dmix->slave_buffer_size;
385 appl_ptr += transfer;
386 appl_ptr %= pcm->buffer_size;
392 * synchronize hardware pointer (hw_ptr) with ours
394 static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
396 snd_pcm_direct_t *dmix = pcm->private_data;
397 snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail;
398 snd_pcm_sframes_t diff;
400 switch (snd_pcm_state(dmix->spcm)) {
401 case SND_PCM_STATE_DISCONNECTED:
402 dmix->state = SND_PCM_STATE_DISCONNECTED;
408 snd_pcm_hwsync(dmix->spcm);
409 old_slave_hw_ptr = dmix->slave_hw_ptr;
410 slave_hw_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
411 diff = slave_hw_ptr - old_slave_hw_ptr;
412 if (diff == 0) /* fast path */
414 if (dmix->state != SND_PCM_STATE_RUNNING &&
415 dmix->state != SND_PCM_STATE_DRAINING)
416 /* not really started yet - don't update hw_ptr */
419 slave_hw_ptr += dmix->slave_boundary;
420 diff = slave_hw_ptr - old_slave_hw_ptr;
422 dmix->hw_ptr += diff;
423 dmix->hw_ptr %= pcm->boundary;
424 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
426 avail = snd_pcm_mmap_playback_avail(pcm);
427 if (avail > dmix->avail_max)
428 dmix->avail_max = avail;
429 if (avail >= pcm->stop_threshold) {
430 snd_timer_stop(dmix->timer);
431 gettimestamp(&dmix->trigger_tstamp, pcm->monotonic);
432 if (dmix->state == SND_PCM_STATE_RUNNING) {
433 dmix->state = SND_PCM_STATE_XRUN;
436 dmix->state = SND_PCM_STATE_SETUP;
437 /* clear queue to remove pending poll events */
438 snd_pcm_direct_clear_timer_queue(dmix);
444 * plugin implementation
447 static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
449 snd_pcm_direct_t *dmix = pcm->private_data;
450 snd_pcm_state_t state;
451 state = snd_pcm_state(dmix->spcm);
453 case SND_PCM_STATE_SUSPENDED:
455 case SND_PCM_STATE_DISCONNECTED:
460 if (dmix->state == STATE_RUN_PENDING)
461 return SNDRV_PCM_STATE_RUNNING;
465 static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
467 snd_pcm_direct_t *dmix = pcm->private_data;
469 switch (dmix->state) {
470 case SNDRV_PCM_STATE_DRAINING:
471 case SNDRV_PCM_STATE_RUNNING:
472 snd_pcm_dmix_sync_ptr(pcm);
477 memset(status, 0, sizeof(*status));
478 status->state = snd_pcm_dmix_state(pcm);
479 status->trigger_tstamp = dmix->trigger_tstamp;
480 gettimestamp(&status->tstamp, pcm->monotonic);
481 status->avail = snd_pcm_mmap_playback_avail(pcm);
482 status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max;
487 static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
489 snd_pcm_direct_t *dmix = pcm->private_data;
492 switch(dmix->state) {
493 case SNDRV_PCM_STATE_DRAINING:
494 case SNDRV_PCM_STATE_RUNNING:
495 err = snd_pcm_dmix_sync_ptr(pcm);
499 case SNDRV_PCM_STATE_PREPARED:
500 case SNDRV_PCM_STATE_SUSPENDED:
501 case STATE_RUN_PENDING:
502 *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
504 case SNDRV_PCM_STATE_XRUN:
506 case SNDRV_PCM_STATE_DISCONNECTED:
513 static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm)
515 snd_pcm_direct_t *dmix = pcm->private_data;
517 switch(dmix->state) {
518 case SNDRV_PCM_STATE_DRAINING:
519 case SNDRV_PCM_STATE_RUNNING:
521 return snd_pcm_dmix_sync_ptr(pcm);
522 case SNDRV_PCM_STATE_PREPARED:
523 case SNDRV_PCM_STATE_SUSPENDED:
524 case STATE_RUN_PENDING:
526 case SNDRV_PCM_STATE_XRUN:
528 case SNDRV_PCM_STATE_DISCONNECTED:
535 static int snd_pcm_dmix_prepare(snd_pcm_t *pcm)
537 snd_pcm_direct_t *dmix = pcm->private_data;
539 snd_pcm_direct_check_interleave(dmix, pcm);
540 dmix->state = SND_PCM_STATE_PREPARED;
541 dmix->appl_ptr = dmix->last_appl_ptr = 0;
543 return snd_pcm_direct_set_timer_params(dmix);
546 static void reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
548 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
549 if (pcm->buffer_size > pcm->period_size * 2)
551 /* If we have too litte periods, better to align the start position
552 * to the period boundary so that the interrupt can be handled properly
555 dmix->slave_appl_ptr = ((dmix->slave_appl_ptr + dmix->slave_period_size - 1)
556 / dmix->slave_period_size) * dmix->slave_period_size;
559 static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
561 snd_pcm_direct_t *dmix = pcm->private_data;
562 dmix->hw_ptr %= pcm->period_size;
563 dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr;
564 reset_slave_ptr(pcm, dmix);
568 static int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
572 snd_pcm_hwsync(dmix->spcm);
573 reset_slave_ptr(pcm, dmix);
574 err = snd_timer_start(dmix->timer);
577 dmix->state = SND_PCM_STATE_RUNNING;
581 static int snd_pcm_dmix_start(snd_pcm_t *pcm)
583 snd_pcm_direct_t *dmix = pcm->private_data;
584 snd_pcm_sframes_t avail;
587 if (dmix->state != SND_PCM_STATE_PREPARED)
589 avail = snd_pcm_mmap_playback_hw_avail(pcm);
591 dmix->state = STATE_RUN_PENDING;
595 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
597 snd_pcm_dmix_sync_area(pcm);
599 gettimestamp(&dmix->trigger_tstamp, pcm->monotonic);
603 static int snd_pcm_dmix_drop(snd_pcm_t *pcm)
605 snd_pcm_direct_t *dmix = pcm->private_data;
606 if (dmix->state == SND_PCM_STATE_OPEN)
608 dmix->state = SND_PCM_STATE_SETUP;
609 snd_pcm_direct_timer_stop(dmix);
613 static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
615 snd_pcm_direct_t *dmix = pcm->private_data;
616 snd_pcm_uframes_t stop_threshold;
619 if (dmix->state == SND_PCM_STATE_OPEN)
621 if (pcm->mode & SND_PCM_NONBLOCK)
623 if (dmix->state == SND_PCM_STATE_PREPARED) {
624 if (snd_pcm_mmap_playback_hw_avail(pcm) > 0)
625 snd_pcm_dmix_start(pcm);
627 snd_pcm_dmix_drop(pcm);
632 if (dmix->state == SND_PCM_STATE_XRUN) {
633 snd_pcm_dmix_drop(pcm);
637 stop_threshold = pcm->stop_threshold;
638 if (pcm->stop_threshold > pcm->buffer_size)
639 pcm->stop_threshold = pcm->buffer_size;
640 dmix->state = SND_PCM_STATE_DRAINING;
642 err = snd_pcm_dmix_sync_ptr(pcm);
644 snd_pcm_dmix_drop(pcm);
647 if (dmix->state == SND_PCM_STATE_DRAINING) {
648 snd_pcm_dmix_sync_area(pcm);
649 snd_pcm_wait_nocheck(pcm, -1);
650 snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */
652 } while (dmix->state == SND_PCM_STATE_DRAINING);
653 pcm->stop_threshold = stop_threshold;
657 static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
662 static snd_pcm_sframes_t snd_pcm_dmix_rewindable(snd_pcm_t *pcm)
664 return snd_pcm_mmap_hw_avail(pcm);
667 static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
669 snd_pcm_direct_t *dmix = pcm->private_data;
670 snd_pcm_uframes_t slave_appl_ptr, slave_size;
671 snd_pcm_uframes_t appl_ptr, size, transfer, result;
672 const snd_pcm_channel_area_t *src_areas, *dst_areas;
674 if (dmix->state == SND_PCM_STATE_RUNNING ||
675 dmix->state == SND_PCM_STATE_DRAINING)
676 return snd_pcm_dmix_hwsync(pcm);
678 if (dmix->last_appl_ptr < dmix->appl_ptr)
679 size = dmix->appl_ptr - dmix->last_appl_ptr;
681 size = dmix->appl_ptr + (pcm->boundary - dmix->last_appl_ptr);
684 snd_pcm_mmap_appl_backward(pcm, size);
690 if (dmix->hw_ptr < dmix->appl_ptr)
691 size = dmix->appl_ptr - dmix->hw_ptr;
693 size = dmix->appl_ptr + (pcm->boundary - dmix->hw_ptr);
696 if (dmix->slave_hw_ptr < dmix->slave_appl_ptr)
697 slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr;
699 slave_size = dmix->slave_appl_ptr + (pcm->boundary - dmix->slave_hw_ptr);
700 if (slave_size < size)
705 /* add sample areas here */
706 src_areas = snd_pcm_mmap_areas(pcm);
707 dst_areas = snd_pcm_mmap_areas(dmix->spcm);
708 dmix->last_appl_ptr -= size;
709 dmix->last_appl_ptr %= pcm->boundary;
710 appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
711 dmix->slave_appl_ptr -= size;
712 dmix->slave_appl_ptr %= dmix->slave_boundary;
713 slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
717 if (appl_ptr + transfer > pcm->buffer_size)
718 transfer = pcm->buffer_size - appl_ptr;
719 if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
720 transfer = dmix->slave_buffer_size - slave_appl_ptr;
721 remix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
725 slave_appl_ptr += transfer;
726 slave_appl_ptr %= dmix->slave_buffer_size;
727 appl_ptr += transfer;
728 appl_ptr %= pcm->buffer_size;
730 dmix->last_appl_ptr -= frames;
731 dmix->last_appl_ptr %= pcm->boundary;
732 dmix->slave_appl_ptr -= frames;
733 dmix->slave_appl_ptr %= dmix->slave_boundary;
736 snd_pcm_mmap_appl_backward(pcm, frames);
738 return result + frames;
741 static snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm)
743 return snd_pcm_mmap_avail(pcm);
746 static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
748 snd_pcm_sframes_t avail;
750 avail = snd_pcm_mmap_playback_avail(pcm);
753 if (frames > (snd_pcm_uframes_t)avail)
755 snd_pcm_mmap_appl_forward(pcm, frames);
759 static snd_pcm_sframes_t snd_pcm_dmix_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
764 static snd_pcm_sframes_t snd_pcm_dmix_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
769 static int snd_pcm_dmix_close(snd_pcm_t *pcm)
771 snd_pcm_direct_t *dmix = pcm->private_data;
774 snd_timer_close(dmix->timer);
775 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
776 snd_pcm_close(dmix->spcm);
778 snd_pcm_direct_server_discard(dmix);
780 snd_pcm_direct_client_discard(dmix);
781 shm_sum_discard(dmix);
782 if (snd_pcm_direct_shm_discard(dmix)) {
783 if (snd_pcm_direct_semaphore_discard(dmix))
784 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
786 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
787 free(dmix->bindings);
788 pcm->private_data = NULL;
793 static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
794 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
795 snd_pcm_uframes_t size)
797 snd_pcm_direct_t *dmix = pcm->private_data;
800 switch (snd_pcm_state(dmix->spcm)) {
801 case SND_PCM_STATE_XRUN:
803 case SND_PCM_STATE_SUSPENDED:
810 snd_pcm_mmap_appl_forward(pcm, size);
811 if (dmix->state == STATE_RUN_PENDING) {
812 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
814 } else if (dmix->state == SND_PCM_STATE_RUNNING ||
815 dmix->state == SND_PCM_STATE_DRAINING)
816 snd_pcm_dmix_sync_ptr(pcm);
817 if (dmix->state == SND_PCM_STATE_RUNNING ||
818 dmix->state == SND_PCM_STATE_DRAINING) {
819 /* ok, we commit the changes after the validation of area */
820 /* it's intended, although the result might be crappy */
821 snd_pcm_dmix_sync_area(pcm);
822 /* clear timer queue to avoid a bogus return from poll */
823 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
824 snd_pcm_direct_clear_timer_queue(dmix);
829 static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm)
831 snd_pcm_direct_t *dmix = pcm->private_data;
833 if (dmix->state == SND_PCM_STATE_RUNNING ||
834 dmix->state == SND_PCM_STATE_DRAINING)
835 snd_pcm_dmix_sync_ptr(pcm);
836 return snd_pcm_mmap_playback_avail(pcm);
839 static int snd_pcm_dmix_htimestamp(snd_pcm_t *pcm,
840 snd_pcm_uframes_t *avail,
841 snd_htimestamp_t *tstamp)
843 snd_pcm_direct_t *dmix = pcm->private_data;
844 snd_pcm_uframes_t avail1;
848 if (dmix->state == SND_PCM_STATE_RUNNING ||
849 dmix->state == SND_PCM_STATE_DRAINING)
850 snd_pcm_dmix_sync_ptr(pcm);
851 avail1 = snd_pcm_mmap_playback_avail(pcm);
852 if (ok && *avail == avail1)
855 *tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
860 static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
862 snd_pcm_direct_t *dmix = pcm->private_data;
863 if (dmix->state == SND_PCM_STATE_RUNNING)
864 snd_pcm_dmix_sync_area(pcm);
865 return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents);
869 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
871 snd_pcm_direct_t *dmix = pcm->private_data;
873 snd_output_printf(out, "Direct Stream Mixing PCM\n");
875 snd_output_printf(out, "Its setup is:\n");
876 snd_pcm_dump_setup(pcm, out);
879 snd_pcm_dump(dmix->spcm, out);
882 static const snd_pcm_ops_t snd_pcm_dmix_ops = {
883 .close = snd_pcm_dmix_close,
884 .info = snd_pcm_direct_info,
885 .hw_refine = snd_pcm_direct_hw_refine,
886 .hw_params = snd_pcm_direct_hw_params,
887 .hw_free = snd_pcm_direct_hw_free,
888 .sw_params = snd_pcm_direct_sw_params,
889 .channel_info = snd_pcm_direct_channel_info,
890 .dump = snd_pcm_dmix_dump,
891 .nonblock = snd_pcm_direct_nonblock,
892 .async = snd_pcm_direct_async,
893 .mmap = snd_pcm_direct_mmap,
894 .munmap = snd_pcm_direct_munmap,
897 static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
898 .status = snd_pcm_dmix_status,
899 .state = snd_pcm_dmix_state,
900 .hwsync = snd_pcm_dmix_hwsync,
901 .delay = snd_pcm_dmix_delay,
902 .prepare = snd_pcm_dmix_prepare,
903 .reset = snd_pcm_dmix_reset,
904 .start = snd_pcm_dmix_start,
905 .drop = snd_pcm_dmix_drop,
906 .drain = snd_pcm_dmix_drain,
907 .pause = snd_pcm_dmix_pause,
908 .rewindable = snd_pcm_dmix_rewindable,
909 .rewind = snd_pcm_dmix_rewind,
910 .forwardable = snd_pcm_dmix_forwardable,
911 .forward = snd_pcm_dmix_forward,
912 .resume = snd_pcm_direct_resume,
916 .writei = snd_pcm_mmap_writei,
917 .writen = snd_pcm_mmap_writen,
918 .readi = snd_pcm_dmix_readi,
919 .readn = snd_pcm_dmix_readn,
920 .avail_update = snd_pcm_dmix_avail_update,
921 .mmap_commit = snd_pcm_dmix_mmap_commit,
922 .htimestamp = snd_pcm_dmix_htimestamp,
923 .poll_descriptors = NULL,
924 .poll_descriptors_count = NULL,
925 .poll_revents = snd_pcm_dmix_poll_revents,
929 * \brief Creates a new dmix PCM
930 * \param pcmp Returns created PCM handle
931 * \param name Name of PCM
932 * \param opts Direct PCM configurations
933 * \param params Parameters for slave
934 * \param root Configuration root
935 * \param sconf Slave configuration
936 * \param stream PCM Direction (stream)
937 * \param mode PCM Mode
938 * \retval zero on success otherwise a negative error code
939 * \warning Using of this function might be dangerous in the sense
940 * of compatibility reasons. The prototype might be freely
943 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
944 struct snd_pcm_direct_open_conf *opts,
945 struct slave_params *params,
946 snd_config_t *root, snd_config_t *sconf,
947 snd_pcm_stream_t stream, int mode)
949 snd_pcm_t *pcm = NULL, *spcm = NULL;
950 snd_pcm_direct_t *dmix = NULL;
951 int ret, first_instance;
952 int fail_sem_loop = 10;
956 if (stream != SND_PCM_STREAM_PLAYBACK) {
957 SNDERR("The dmix plugin supports only playback stream");
961 dmix = calloc(1, sizeof(snd_pcm_direct_t));
967 ret = snd_pcm_direct_parse_bindings(dmix, params, opts->bindings);
971 dmix->ipc_key = opts->ipc_key;
972 dmix->ipc_perm = opts->ipc_perm;
973 dmix->ipc_gid = opts->ipc_gid;
977 ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode);
983 ret = snd_pcm_direct_semaphore_create_or_connect(dmix);
985 SNDERR("unable to create IPC semaphore");
988 ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
990 snd_pcm_direct_semaphore_discard(dmix);
991 if (--fail_sem_loop <= 0)
998 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix);
1000 SNDERR("unable to create IPC shm instance");
1004 pcm->ops = &snd_pcm_dmix_ops;
1005 pcm->fast_ops = &snd_pcm_dmix_fast_ops;
1006 pcm->private_data = dmix;
1007 dmix->state = SND_PCM_STATE_OPEN;
1008 dmix->slowptr = opts->slowptr;
1009 dmix->max_periods = opts->max_periods;
1010 dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
1012 if (first_instance) {
1013 /* recursion is already checked in
1014 snd_pcm_direct_get_slave_ipc_offset() */
1015 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1016 mode | SND_PCM_NONBLOCK, NULL);
1018 SNDERR("unable to open slave");
1022 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1023 SNDERR("dmix plugin can be only connected to hw plugin");
1028 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
1030 SNDERR("unable to initialize slave");
1036 if (dmix->shmptr->use_server) {
1037 dmix->server_free = dmix_server_free;
1039 ret = snd_pcm_direct_server_create(dmix);
1041 SNDERR("unable to create server");
1046 dmix->shmptr->type = spcm->type;
1048 if (dmix->shmptr->use_server) {
1049 /* up semaphore to avoid deadlock */
1050 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1051 ret = snd_pcm_direct_client_connect(dmix);
1053 SNDERR("unable to connect client");
1057 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
1058 ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client");
1063 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1064 mode | SND_PCM_NONBLOCK |
1068 SNDERR("unable to open slave");
1071 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1072 SNDERR("dmix plugin can be only connected to hw plugin");
1077 ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params);
1079 SNDERR("unable to initialize slave");
1087 ret = shm_sum_create_or_connect(dmix);
1089 SNDERR("unable to initialize sum ring buffer");
1093 ret = snd_pcm_direct_initialize_poll_fd(dmix);
1095 SNDERR("unable to initialize poll_fd");
1099 mix_select_callbacks(dmix);
1101 pcm->poll_fd = dmix->poll_fd;
1102 pcm->poll_events = POLLIN; /* it's different than other plugins */
1105 snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
1106 snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
1108 if (dmix->channels == UINT_MAX)
1109 dmix->channels = dmix->shmptr->s.channels;
1111 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1118 snd_timer_close(dmix->timer);
1120 snd_pcm_direct_server_discard(dmix);
1122 snd_pcm_direct_client_discard(dmix);
1124 snd_pcm_close(spcm);
1125 if (dmix->u.dmix.shmid_sum >= 0)
1126 shm_sum_discard(dmix);
1127 if (dmix->shmid >= 0)
1128 snd_pcm_direct_shm_discard(dmix);
1129 if (snd_pcm_direct_semaphore_discard(dmix) < 0)
1130 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1133 free(dmix->bindings);
1141 /*! \page pcm_plugins
1143 \section pcm_plugins_dmix Plugin: dmix
1145 This plugin provides direct mixing of multiple streams. The resolution
1146 for 32-bit mixing is only 24-bit. The low significant byte is filled with
1147 zeros. The extra 8 bits are used for the saturation.
1151 type dmix # Direct mix
1152 ipc_key INT # unique IPC key
1153 ipc_key_add_uid BOOL # add current uid to unique IPC key
1154 ipc_perm INT # IPC permissions (octal, default 0600)
1157 slave { # Slave definition
1158 pcm STR # slave PCM name
1160 pcm { } # slave PCM definition
1161 format STR # format definition
1162 rate INT # rate definition
1164 period_time INT # in usec
1166 period_size INT # in bytes
1167 buffer_time INT # in usec
1169 buffer_size INT # in bytes
1170 periods INT # when buffer_size or buffer_time is not specified
1172 bindings { # note: this is client independent!!!
1173 N INT # maps slave channel to client channel N
1175 slowptr BOOL # slow but more precise pointer updates
1179 <code>ipc_key</code> specfies the unique IPC key in integer.
1180 This number must be unique for each different dmix definition,
1181 since the shared memory is created with this key number.
1182 When <code>ipc_key_add_uid</code> is set true, the uid value is
1183 added to the value set in <code>ipc_key</code>. This will
1184 avoid the confliction of the same IPC key with different users
1187 Note that the dmix plugin itself supports only a single configuration.
1188 That is, it supports only the fixed rate (default 48000), format
1189 (\c S16), channels (2), and period_time (125000).
1190 For using other configuration, you have to set the value explicitly
1191 in the slave PCM definition. The rate, format and channels can be
1192 covered by an additional \ref pcm_plugins_dmix "plug plugin",
1193 but there is only one base configuration, anyway.
1195 An example configuration for setting 44100 Hz, \c S32_LE format
1196 as the slave PCM of "hw:0" is like below:
1200 ipc_key 321456 # any unique value
1201 ipc_key_add_uid true
1209 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
1212 % aplay -Dplug:dmix_44 foo_48k.wav
1215 For using the dmix plugin for OSS emulation device, you have to set
1216 the period and the buffer sizes in power of two. For example,
1220 ipc_key 321456 # any unique value
1221 ipc_key_add_uid true
1225 period_size 1024 # must be power of 2
1226 buffer_size 8192 # ditto
1230 <code>period_time 0</code> must be set, too, for resetting the
1231 default value. In the case of soundcards with multi-channel IO,
1232 adding the bindings would help
1237 0 0 # map from 0 to 0
1238 1 1 # map from 1 to 1
1242 so that only the first two channels are used by dmix.
1243 Also, note that ICE1712 have the limited buffer size, 5513 frames
1244 (corresponding to 640 kB). In this case, reduce the buffer_size
1247 \subsection pcm_plugins_dmix_funcref Function reference
1250 <LI>snd_pcm_dmix_open()
1251 <LI>_snd_pcm_dmix_open()
1257 * \brief Creates a new dmix PCM
1258 * \param pcmp Returns created PCM handle
1259 * \param name Name of PCM
1260 * \param root Root configuration node
1261 * \param conf Configuration node with dmix PCM description
1262 * \param stream PCM Stream
1263 * \param mode PCM Mode
1264 * \warning Using of this function might be dangerous in the sense
1265 * of compatibility reasons. The prototype might be freely
1266 * changed in future.
1268 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
1269 snd_config_t *root, snd_config_t *conf,
1270 snd_pcm_stream_t stream, int mode)
1272 snd_config_t *sconf;
1273 struct slave_params params;
1274 struct snd_pcm_direct_open_conf dopen;
1278 err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
1282 /* the default settings, it might be invalid for some hardware */
1283 params.format = SND_PCM_FORMAT_S16;
1284 params.rate = 48000;
1285 params.channels = 2;
1286 params.period_time = -1;
1287 params.buffer_time = -1;
1291 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
1292 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format,
1293 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
1294 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
1295 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
1296 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
1297 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1298 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1299 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
1303 /* set a reasonable default */
1304 if (psize == -1 && params.period_time == -1)
1305 params.period_time = 125000; /* 0.125 seconds */
1307 if (params.format == -2)
1308 params.format = SND_PCM_FORMAT_UNKNOWN;
1309 else if (!(dmix_supported_format & (1ULL << params.format))) {
1310 /* sorry, limited features */
1311 SNDERR("Unsupported format");
1312 snd_config_delete(sconf);
1316 params.period_size = psize;
1317 params.buffer_size = bsize;
1319 err = snd_pcm_dmix_open(pcmp, name, &dopen, ¶ms,
1320 root, sconf, stream, mode);
1321 snd_config_delete(sconf);
1325 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);