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_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr)
396 snd_pcm_direct_t *dmix = pcm->private_data;
397 snd_pcm_uframes_t old_slave_hw_ptr, avail;
398 snd_pcm_sframes_t diff;
400 old_slave_hw_ptr = dmix->slave_hw_ptr;
401 dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
402 diff = slave_hw_ptr - old_slave_hw_ptr;
403 if (diff == 0) /* fast path */
405 if (dmix->state != SND_PCM_STATE_RUNNING &&
406 dmix->state != SND_PCM_STATE_DRAINING)
407 /* not really started yet - don't update hw_ptr */
410 slave_hw_ptr += dmix->slave_boundary;
411 diff = slave_hw_ptr - old_slave_hw_ptr;
413 dmix->hw_ptr += diff;
414 dmix->hw_ptr %= pcm->boundary;
415 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
417 avail = snd_pcm_mmap_playback_avail(pcm);
418 if (avail > dmix->avail_max)
419 dmix->avail_max = avail;
420 if (avail >= pcm->stop_threshold) {
421 snd_timer_stop(dmix->timer);
422 gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type);
423 if (dmix->state == SND_PCM_STATE_RUNNING) {
424 dmix->state = SND_PCM_STATE_XRUN;
427 dmix->state = SND_PCM_STATE_SETUP;
428 /* clear queue to remove pending poll events */
429 snd_pcm_direct_clear_timer_queue(dmix);
434 static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
436 snd_pcm_direct_t *dmix = pcm->private_data;
439 switch (snd_pcm_state(dmix->spcm)) {
440 case SND_PCM_STATE_DISCONNECTED:
441 dmix->state = SND_PCM_STATE_DISCONNECTED;
443 case SND_PCM_STATE_XRUN:
444 if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
450 if (snd_pcm_direct_client_chk_xrun(dmix, pcm))
453 snd_pcm_hwsync(dmix->spcm);
455 return snd_pcm_dmix_sync_ptr0(pcm, *dmix->spcm->hw.ptr);
459 * plugin implementation
462 static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
464 snd_pcm_direct_t *dmix = pcm->private_data;
466 snd_pcm_state_t state;
467 state = snd_pcm_state(dmix->spcm);
469 case SND_PCM_STATE_SUSPENDED:
470 case SND_PCM_STATE_DISCONNECTED:
473 case SND_PCM_STATE_XRUN:
474 if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
480 snd_pcm_direct_client_chk_xrun(dmix, pcm);
481 if (dmix->state == STATE_RUN_PENDING)
482 return SNDRV_PCM_STATE_RUNNING;
486 static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
488 snd_pcm_direct_t *dmix = pcm->private_data;
490 memset(status, 0, sizeof(*status));
491 snd_pcm_status(dmix->spcm, status);
493 switch (dmix->state) {
494 case SNDRV_PCM_STATE_DRAINING:
495 case SNDRV_PCM_STATE_RUNNING:
496 snd_pcm_dmix_sync_ptr0(pcm, status->hw_ptr);
497 status->delay += snd_pcm_mmap_playback_delay(pcm)
498 + status->avail - dmix->spcm->buffer_size;
504 status->trigger_tstamp = dmix->trigger_tstamp;
505 status->avail = snd_pcm_mmap_playback_avail(pcm);
506 status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max;
511 static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
513 snd_pcm_direct_t *dmix = pcm->private_data;
516 switch(dmix->state) {
517 case SNDRV_PCM_STATE_DRAINING:
518 case SNDRV_PCM_STATE_RUNNING:
519 err = snd_pcm_dmix_sync_ptr(pcm);
523 case SNDRV_PCM_STATE_PREPARED:
524 case SNDRV_PCM_STATE_SUSPENDED:
525 case STATE_RUN_PENDING:
526 *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
528 case SNDRV_PCM_STATE_XRUN:
530 case SNDRV_PCM_STATE_DISCONNECTED:
537 static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm)
539 snd_pcm_direct_t *dmix = pcm->private_data;
541 switch(dmix->state) {
542 case SNDRV_PCM_STATE_DRAINING:
543 case SNDRV_PCM_STATE_RUNNING:
545 return snd_pcm_dmix_sync_ptr(pcm);
546 case SNDRV_PCM_STATE_PREPARED:
547 case SNDRV_PCM_STATE_SUSPENDED:
548 case STATE_RUN_PENDING:
550 case SNDRV_PCM_STATE_XRUN:
552 case SNDRV_PCM_STATE_DISCONNECTED:
559 static void reset_slave_ptr(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
561 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
562 if (pcm->buffer_size > pcm->period_size * 2)
564 /* If we have too litte periods, better to align the start position
565 * to the period boundary so that the interrupt can be handled properly
568 dmix->slave_appl_ptr = ((dmix->slave_appl_ptr + dmix->slave_period_size - 1)
569 / dmix->slave_period_size) * dmix->slave_period_size;
572 static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
574 snd_pcm_direct_t *dmix = pcm->private_data;
575 dmix->hw_ptr %= pcm->period_size;
576 dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr;
577 reset_slave_ptr(pcm, dmix);
581 static int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
585 snd_pcm_hwsync(dmix->spcm);
586 reset_slave_ptr(pcm, dmix);
587 err = snd_timer_start(dmix->timer);
590 dmix->state = SND_PCM_STATE_RUNNING;
594 static int snd_pcm_dmix_start(snd_pcm_t *pcm)
596 snd_pcm_direct_t *dmix = pcm->private_data;
597 snd_pcm_sframes_t avail;
600 if (dmix->state != SND_PCM_STATE_PREPARED)
602 avail = snd_pcm_mmap_playback_hw_avail(pcm);
604 dmix->state = STATE_RUN_PENDING;
608 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
610 snd_pcm_dmix_sync_area(pcm);
612 gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type);
616 static int snd_pcm_dmix_drop(snd_pcm_t *pcm)
618 snd_pcm_direct_t *dmix = pcm->private_data;
619 if (dmix->state == SND_PCM_STATE_OPEN)
621 dmix->state = SND_PCM_STATE_SETUP;
622 snd_pcm_direct_timer_stop(dmix);
627 static int __snd_pcm_dmix_drain(snd_pcm_t *pcm)
629 snd_pcm_direct_t *dmix = pcm->private_data;
630 snd_pcm_uframes_t stop_threshold;
633 switch (snd_pcm_state(dmix->spcm)) {
634 case SND_PCM_STATE_SUSPENDED:
640 if (dmix->state == SND_PCM_STATE_OPEN)
642 if (pcm->mode & SND_PCM_NONBLOCK)
644 if (dmix->state == SND_PCM_STATE_PREPARED) {
645 if (snd_pcm_mmap_playback_hw_avail(pcm) > 0)
646 snd_pcm_dmix_start(pcm);
648 snd_pcm_dmix_drop(pcm);
653 if (dmix->state == SND_PCM_STATE_XRUN) {
654 snd_pcm_dmix_drop(pcm);
658 stop_threshold = pcm->stop_threshold;
659 if (pcm->stop_threshold > pcm->buffer_size)
660 pcm->stop_threshold = pcm->buffer_size;
661 dmix->state = SND_PCM_STATE_DRAINING;
663 err = snd_pcm_dmix_sync_ptr(pcm);
665 snd_pcm_dmix_drop(pcm);
668 if (dmix->state == SND_PCM_STATE_DRAINING) {
669 snd_pcm_dmix_sync_area(pcm);
670 snd_pcm_wait_nocheck(pcm, -1);
671 snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */
673 switch (snd_pcm_state(dmix->spcm)) {
674 case SND_PCM_STATE_SUSPENDED:
680 } while (dmix->state == SND_PCM_STATE_DRAINING);
681 pcm->stop_threshold = stop_threshold;
685 static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
690 err = __snd_pcm_dmix_drain(pcm);
695 static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
700 static snd_pcm_sframes_t snd_pcm_dmix_rewindable(snd_pcm_t *pcm)
702 return snd_pcm_mmap_playback_hw_rewindable(pcm);
705 static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
707 snd_pcm_direct_t *dmix = pcm->private_data;
708 snd_pcm_uframes_t slave_appl_ptr, slave_size;
709 snd_pcm_uframes_t appl_ptr, size, transfer, result;
711 const snd_pcm_channel_area_t *src_areas, *dst_areas;
713 if (dmix->state == SND_PCM_STATE_RUNNING ||
714 dmix->state == SND_PCM_STATE_DRAINING) {
715 err = snd_pcm_dmix_hwsync(pcm);
720 if (dmix->last_appl_ptr < dmix->appl_ptr)
721 size = dmix->appl_ptr - dmix->last_appl_ptr;
723 size = dmix->appl_ptr + (pcm->boundary - dmix->last_appl_ptr);
726 snd_pcm_mmap_appl_backward(pcm, size);
732 if (dmix->hw_ptr < dmix->appl_ptr)
733 size = dmix->appl_ptr - dmix->hw_ptr;
735 size = dmix->appl_ptr + (pcm->boundary - dmix->hw_ptr);
738 if (dmix->slave_hw_ptr < dmix->slave_appl_ptr)
739 slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr;
741 slave_size = dmix->slave_appl_ptr + (pcm->boundary - dmix->slave_hw_ptr);
742 if (slave_size < size)
747 /* add sample areas here */
748 src_areas = snd_pcm_mmap_areas(pcm);
749 dst_areas = snd_pcm_mmap_areas(dmix->spcm);
750 dmix->last_appl_ptr -= size;
751 dmix->last_appl_ptr %= pcm->boundary;
752 appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
753 dmix->slave_appl_ptr -= size;
754 dmix->slave_appl_ptr %= dmix->slave_boundary;
755 slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
759 if (appl_ptr + transfer > pcm->buffer_size)
760 transfer = pcm->buffer_size - appl_ptr;
761 if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
762 transfer = dmix->slave_buffer_size - slave_appl_ptr;
763 remix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
767 slave_appl_ptr += transfer;
768 slave_appl_ptr %= dmix->slave_buffer_size;
769 appl_ptr += transfer;
770 appl_ptr %= pcm->buffer_size;
772 dmix->last_appl_ptr -= frames;
773 dmix->last_appl_ptr %= pcm->boundary;
774 dmix->slave_appl_ptr -= frames;
775 dmix->slave_appl_ptr %= dmix->slave_boundary;
778 snd_pcm_mmap_appl_backward(pcm, frames);
780 return result + frames;
783 static snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm)
785 return snd_pcm_mmap_avail(pcm);
788 static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
790 snd_pcm_sframes_t avail;
792 avail = snd_pcm_dmix_forwardable(pcm);
793 if (frames > (snd_pcm_uframes_t)avail)
795 snd_pcm_mmap_appl_forward(pcm, frames);
799 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)
804 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)
809 static int snd_pcm_dmix_close(snd_pcm_t *pcm)
811 snd_pcm_direct_t *dmix = pcm->private_data;
814 snd_timer_close(dmix->timer);
815 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
816 snd_pcm_close(dmix->spcm);
818 snd_pcm_direct_server_discard(dmix);
820 snd_pcm_direct_client_discard(dmix);
821 shm_sum_discard(dmix);
822 if (snd_pcm_direct_shm_discard(dmix)) {
823 if (snd_pcm_direct_semaphore_discard(dmix))
824 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
826 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
827 free(dmix->bindings);
828 pcm->private_data = NULL;
833 static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
834 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
835 snd_pcm_uframes_t size)
837 snd_pcm_direct_t *dmix = pcm->private_data;
840 switch (snd_pcm_state(dmix->spcm)) {
841 case SND_PCM_STATE_XRUN:
842 if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
845 case SND_PCM_STATE_SUSPENDED:
850 if (snd_pcm_direct_client_chk_xrun(dmix, pcm))
854 snd_pcm_mmap_appl_forward(pcm, size);
855 if (dmix->state == STATE_RUN_PENDING) {
856 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
858 } else if (dmix->state == SND_PCM_STATE_RUNNING ||
859 dmix->state == SND_PCM_STATE_DRAINING) {
860 if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0)
863 if (dmix->state == SND_PCM_STATE_RUNNING ||
864 dmix->state == SND_PCM_STATE_DRAINING) {
865 /* ok, we commit the changes after the validation of area */
866 /* it's intended, although the result might be crappy */
867 snd_pcm_dmix_sync_area(pcm);
868 /* clear timer queue to avoid a bogus return from poll */
869 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
870 snd_pcm_direct_clear_timer_queue(dmix);
875 static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm)
877 snd_pcm_direct_t *dmix = pcm->private_data;
880 if (dmix->state == SND_PCM_STATE_RUNNING ||
881 dmix->state == SND_PCM_STATE_DRAINING) {
882 if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0)
885 return snd_pcm_mmap_playback_avail(pcm);
888 static int snd_pcm_dmix_htimestamp(snd_pcm_t *pcm,
889 snd_pcm_uframes_t *avail,
890 snd_htimestamp_t *tstamp)
892 snd_pcm_direct_t *dmix = pcm->private_data;
893 snd_pcm_uframes_t avail1;
897 if (dmix->state == SND_PCM_STATE_RUNNING ||
898 dmix->state == SND_PCM_STATE_DRAINING)
899 snd_pcm_dmix_sync_ptr(pcm);
900 avail1 = snd_pcm_mmap_playback_avail(pcm);
901 if (ok && *avail == avail1)
904 *tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
910 static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
912 snd_pcm_direct_t *dmix = pcm->private_data;
913 if (dmix->state == SND_PCM_STATE_RUNNING)
914 snd_pcm_dmix_sync_area(pcm);
915 return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents);
919 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
921 snd_pcm_direct_t *dmix = pcm->private_data;
923 snd_output_printf(out, "Direct Stream Mixing PCM\n");
925 snd_output_printf(out, "Its setup is:\n");
926 snd_pcm_dump_setup(pcm, out);
929 snd_pcm_dump(dmix->spcm, out);
932 static const snd_pcm_ops_t snd_pcm_dmix_ops = {
933 .close = snd_pcm_dmix_close,
934 .info = snd_pcm_direct_info,
935 .hw_refine = snd_pcm_direct_hw_refine,
936 .hw_params = snd_pcm_direct_hw_params,
937 .hw_free = snd_pcm_direct_hw_free,
938 .sw_params = snd_pcm_direct_sw_params,
939 .channel_info = snd_pcm_direct_channel_info,
940 .dump = snd_pcm_dmix_dump,
941 .nonblock = snd_pcm_direct_nonblock,
942 .async = snd_pcm_direct_async,
943 .mmap = snd_pcm_direct_mmap,
944 .munmap = snd_pcm_direct_munmap,
945 .query_chmaps = snd_pcm_direct_query_chmaps,
946 .get_chmap = snd_pcm_direct_get_chmap,
947 .set_chmap = snd_pcm_direct_set_chmap,
950 static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
951 .status = snd_pcm_dmix_status,
952 .state = snd_pcm_dmix_state,
953 .hwsync = snd_pcm_dmix_hwsync,
954 .delay = snd_pcm_dmix_delay,
955 .prepare = snd_pcm_direct_prepare,
956 .reset = snd_pcm_dmix_reset,
957 .start = snd_pcm_dmix_start,
958 .drop = snd_pcm_dmix_drop,
959 .drain = snd_pcm_dmix_drain,
960 .pause = snd_pcm_dmix_pause,
961 .rewindable = snd_pcm_dmix_rewindable,
962 .rewind = snd_pcm_dmix_rewind,
963 .forwardable = snd_pcm_dmix_forwardable,
964 .forward = snd_pcm_dmix_forward,
965 .resume = snd_pcm_direct_resume,
969 .writei = snd_pcm_mmap_writei,
970 .writen = snd_pcm_mmap_writen,
971 .readi = snd_pcm_dmix_readi,
972 .readn = snd_pcm_dmix_readn,
973 .avail_update = snd_pcm_dmix_avail_update,
974 .mmap_commit = snd_pcm_dmix_mmap_commit,
975 .htimestamp = snd_pcm_dmix_htimestamp,
976 .poll_descriptors = snd_pcm_direct_poll_descriptors,
977 .poll_descriptors_count = NULL,
978 .poll_revents = snd_pcm_dmix_poll_revents,
982 * \brief Creates a new dmix PCM
983 * \param pcmp Returns created PCM handle
984 * \param name Name of PCM
985 * \param opts Direct PCM configurations
986 * \param params Parameters for slave
987 * \param root Configuration root
988 * \param sconf Slave configuration
989 * \param stream PCM Direction (stream)
990 * \param mode PCM Mode
991 * \retval zero on success otherwise a negative error code
992 * \warning Using of this function might be dangerous in the sense
993 * of compatibility reasons. The prototype might be freely
996 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
997 struct snd_pcm_direct_open_conf *opts,
998 struct slave_params *params,
999 snd_config_t *root, snd_config_t *sconf,
1000 snd_pcm_stream_t stream, int mode)
1002 snd_pcm_t *pcm = NULL, *spcm = NULL;
1003 snd_pcm_direct_t *dmix = NULL;
1004 int ret, first_instance;
1005 int fail_sem_loop = 10;
1009 if (stream != SND_PCM_STREAM_PLAYBACK) {
1010 SNDERR("The dmix plugin supports only playback stream");
1014 dmix = calloc(1, sizeof(snd_pcm_direct_t));
1020 ret = snd_pcm_direct_parse_bindings(dmix, params, opts->bindings);
1024 dmix->ipc_key = opts->ipc_key;
1025 dmix->ipc_perm = opts->ipc_perm;
1026 dmix->ipc_gid = opts->ipc_gid;
1030 ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode);
1036 ret = snd_pcm_direct_semaphore_create_or_connect(dmix);
1038 SNDERR("unable to create IPC semaphore");
1041 ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
1043 snd_pcm_direct_semaphore_discard(dmix);
1044 if (--fail_sem_loop <= 0)
1051 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix);
1053 SNDERR("unable to create IPC shm instance");
1057 pcm->ops = &snd_pcm_dmix_ops;
1058 pcm->fast_ops = &snd_pcm_dmix_fast_ops;
1059 pcm->private_data = dmix;
1060 dmix->state = SND_PCM_STATE_OPEN;
1061 dmix->slowptr = opts->slowptr;
1062 dmix->max_periods = opts->max_periods;
1063 dmix->var_periodsize = opts->var_periodsize;
1064 dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
1067 if (first_instance) {
1068 /* recursion is already checked in
1069 snd_pcm_direct_get_slave_ipc_offset() */
1070 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1071 mode | SND_PCM_NONBLOCK, NULL);
1073 SNDERR("unable to open slave");
1077 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1078 SNDERR("dmix plugin can be only connected to hw plugin");
1083 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
1085 SNDERR("unable to initialize slave");
1091 if (dmix->shmptr->use_server) {
1092 dmix->server_free = dmix_server_free;
1094 ret = snd_pcm_direct_server_create(dmix);
1096 SNDERR("unable to create server");
1101 dmix->shmptr->type = spcm->type;
1103 if (dmix->shmptr->use_server) {
1104 /* up semaphore to avoid deadlock */
1105 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1106 ret = snd_pcm_direct_client_connect(dmix);
1108 SNDERR("unable to connect client");
1112 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
1113 ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client");
1118 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1119 mode | SND_PCM_NONBLOCK |
1123 /* all other streams have been closed;
1124 * retry as the first instance
1126 if (ret == -EBADFD) {
1130 SNDERR("unable to open slave");
1133 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1134 SNDERR("dmix plugin can be only connected to hw plugin");
1139 ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params);
1141 SNDERR("unable to initialize slave");
1149 ret = shm_sum_create_or_connect(dmix);
1151 SNDERR("unable to initialize sum ring buffer");
1155 ret = snd_pcm_direct_initialize_poll_fd(dmix);
1157 SNDERR("unable to initialize poll_fd");
1161 mix_select_callbacks(dmix);
1163 pcm->poll_fd = dmix->poll_fd;
1164 pcm->poll_events = POLLIN; /* it's different than other plugins */
1165 pcm->tstamp_type = spcm->tstamp_type;
1167 snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
1168 snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
1170 if (dmix->channels == UINT_MAX)
1171 dmix->channels = dmix->shmptr->s.channels;
1173 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1180 snd_timer_close(dmix->timer);
1182 snd_pcm_direct_server_discard(dmix);
1184 snd_pcm_direct_client_discard(dmix);
1186 snd_pcm_close(spcm);
1187 if (dmix->u.dmix.shmid_sum >= 0)
1188 shm_sum_discard(dmix);
1189 if ((dmix->shmid >= 0) && (snd_pcm_direct_shm_discard(dmix))) {
1190 if (snd_pcm_direct_semaphore_discard(dmix))
1191 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
1193 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1196 free(dmix->bindings);
1204 /*! \page pcm_plugins
1206 \section pcm_plugins_dmix Plugin: dmix
1208 This plugin provides direct mixing of multiple streams. The resolution
1209 for 32-bit mixing is only 24-bit. The low significant byte is filled with
1210 zeros. The extra 8 bits are used for the saturation.
1214 type dmix # Direct mix
1215 ipc_key INT # unique IPC key
1216 ipc_key_add_uid BOOL # add current uid to unique IPC key
1217 ipc_perm INT # IPC permissions (octal, default 0600)
1220 slave { # Slave definition
1221 pcm STR # slave PCM name
1223 pcm { } # slave PCM definition
1224 format STR # format definition
1225 rate INT # rate definition
1227 period_time INT # in usec
1229 period_size INT # in bytes
1230 buffer_time INT # in usec
1232 buffer_size INT # in bytes
1233 periods INT # when buffer_size or buffer_time is not specified
1235 bindings { # note: this is client independent!!!
1236 N INT # maps slave channel to client channel N
1238 slowptr BOOL # slow but more precise pointer updates
1242 <code>ipc_key</code> specfies the unique IPC key in integer.
1243 This number must be unique for each different dmix definition,
1244 since the shared memory is created with this key number.
1245 When <code>ipc_key_add_uid</code> is set true, the uid value is
1246 added to the value set in <code>ipc_key</code>. This will
1247 avoid the confliction of the same IPC key with different users
1250 Note that the dmix plugin itself supports only a single configuration.
1251 That is, it supports only the fixed rate (default 48000), format
1252 (\c S16), channels (2), and period_time (125000).
1253 For using other configuration, you have to set the value explicitly
1254 in the slave PCM definition. The rate, format and channels can be
1255 covered by an additional \ref pcm_plugins_dmix "plug plugin",
1256 but there is only one base configuration, anyway.
1258 An example configuration for setting 44100 Hz, \c S32_LE format
1259 as the slave PCM of "hw:0" is like below:
1263 ipc_key 321456 # any unique value
1264 ipc_key_add_uid true
1272 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
1275 % aplay -Dplug:dmix_44 foo_48k.wav
1278 For using the dmix plugin for OSS emulation device, you have to set
1279 the period and the buffer sizes in power of two. For example,
1283 ipc_key 321456 # any unique value
1284 ipc_key_add_uid true
1288 period_size 1024 # must be power of 2
1289 buffer_size 8192 # ditto
1293 <code>period_time 0</code> must be set, too, for resetting the
1294 default value. In the case of soundcards with multi-channel IO,
1295 adding the bindings would help
1300 0 0 # map from 0 to 0
1301 1 1 # map from 1 to 1
1305 so that only the first two channels are used by dmix.
1306 Also, note that ICE1712 have the limited buffer size, 5513 frames
1307 (corresponding to 640 kB). In this case, reduce the buffer_size
1310 \subsection pcm_plugins_dmix_funcref Function reference
1313 <LI>snd_pcm_dmix_open()
1314 <LI>_snd_pcm_dmix_open()
1320 * \brief Creates a new dmix PCM
1321 * \param pcmp Returns created PCM handle
1322 * \param name Name of PCM
1323 * \param root Root configuration node
1324 * \param conf Configuration node with dmix PCM description
1325 * \param stream PCM Stream
1326 * \param mode PCM Mode
1327 * \warning Using of this function might be dangerous in the sense
1328 * of compatibility reasons. The prototype might be freely
1329 * changed in future.
1331 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
1332 snd_config_t *root, snd_config_t *conf,
1333 snd_pcm_stream_t stream, int mode)
1335 snd_config_t *sconf;
1336 struct slave_params params;
1337 struct snd_pcm_direct_open_conf dopen;
1341 err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
1345 /* the default settings, it might be invalid for some hardware */
1346 params.format = SND_PCM_FORMAT_S16;
1347 params.rate = 48000;
1348 params.channels = 2;
1349 params.period_time = -1;
1350 params.buffer_time = -1;
1354 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
1355 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format,
1356 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
1357 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
1358 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
1359 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
1360 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1361 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1362 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
1366 /* set a reasonable default */
1367 if (psize == -1 && params.period_time == -1)
1368 params.period_time = 125000; /* 0.125 seconds */
1370 if (params.format == -2)
1371 params.format = SND_PCM_FORMAT_UNKNOWN;
1372 else if (!(dmix_supported_format & (1ULL << params.format))) {
1373 /* sorry, limited features */
1374 SNDERR("Unsupported format");
1375 snd_config_delete(sconf);
1379 params.period_size = psize;
1380 params.buffer_size = bsize;
1382 err = snd_pcm_dmix_open(pcmp, name, &dopen, ¶ms,
1383 root, sconf, stream, mode);
1384 snd_config_delete(sconf);
1388 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);