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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 + dmix->shmptr->s.channels * dst_ofs + dchn,
218 dmix->shmptr->s.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 + dmix->shmptr->s.channels * dst_ofs + dchn,
286 dmix->shmptr->s.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 static void dmix_down_sem(snd_pcm_direct_t *dmix)
297 if (dmix->u.dmix.use_sem)
298 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
301 static void dmix_up_sem(snd_pcm_direct_t *dmix)
303 if (dmix->u.dmix.use_sem)
304 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
309 * synchronize shm ring buffer with hardware
311 static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm)
313 snd_pcm_direct_t *dmix = pcm->private_data;
314 snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size;
315 snd_pcm_uframes_t appl_ptr, size, transfer;
316 const snd_pcm_channel_area_t *src_areas, *dst_areas;
318 /* calculate the size to transfer */
319 /* check the available size in the local buffer
320 * last_appl_ptr keeps the last updated position
322 size = pcm_frame_diff2(dmix->appl_ptr, dmix->last_appl_ptr, pcm->boundary);
326 /* the slave_app_ptr can be far behind the slave_hw_ptr */
327 /* reduce mixing and errors here - just skip not catched writes */
328 slave_size = pcm_frame_diff(dmix->slave_appl_ptr, dmix->slave_hw_ptr, dmix->slave_boundary);
329 if (slave_size > dmix->slave_buffer_size) {
330 transfer = dmix->slave_buffer_size - slave_size;
333 dmix->last_appl_ptr += transfer;
334 dmix->last_appl_ptr %= pcm->boundary;
335 dmix->slave_appl_ptr += transfer;
336 dmix->slave_appl_ptr %= dmix->slave_boundary;
337 size = pcm_frame_diff2(dmix->appl_ptr, dmix->last_appl_ptr, pcm->boundary);
342 /* check the available size in the slave PCM buffer */
343 slave_hw_ptr = dmix->slave_hw_ptr;
344 /* don't write on the last active period - this area may be cleared
345 * by the driver during mix operation...
347 slave_hw_ptr -= slave_hw_ptr % dmix->slave_period_size;
348 slave_hw_ptr += dmix->slave_buffer_size;
349 if (slave_hw_ptr >= dmix->slave_boundary)
350 slave_hw_ptr -= dmix->slave_boundary;
351 slave_size = pcm_frame_diff(slave_hw_ptr, dmix->slave_appl_ptr, dmix->slave_boundary);
352 if (slave_size < size)
357 /* add sample areas here */
358 src_areas = snd_pcm_mmap_areas(pcm);
359 dst_areas = snd_pcm_mmap_areas(dmix->spcm);
360 appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
361 dmix->last_appl_ptr += size;
362 dmix->last_appl_ptr %= pcm->boundary;
363 slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
364 dmix->slave_appl_ptr += size;
365 dmix->slave_appl_ptr %= dmix->slave_boundary;
369 if (appl_ptr + transfer > pcm->buffer_size)
370 transfer = pcm->buffer_size - appl_ptr;
371 if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
372 transfer = dmix->slave_buffer_size - slave_appl_ptr;
373 mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
377 slave_appl_ptr += transfer;
378 slave_appl_ptr %= dmix->slave_buffer_size;
379 appl_ptr += transfer;
380 appl_ptr %= pcm->buffer_size;
386 * synchronize hardware pointer (hw_ptr) with ours
388 static int snd_pcm_dmix_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr)
390 snd_pcm_direct_t *dmix = pcm->private_data;
391 snd_pcm_uframes_t old_slave_hw_ptr, avail;
392 snd_pcm_sframes_t diff;
394 old_slave_hw_ptr = dmix->slave_hw_ptr;
395 dmix->slave_hw_ptr = slave_hw_ptr;
396 diff = slave_hw_ptr - old_slave_hw_ptr;
397 if (diff == 0) /* fast path */
399 if (dmix->state != SND_PCM_STATE_RUNNING &&
400 dmix->state != SND_PCM_STATE_DRAINING)
401 /* not really started yet - don't update hw_ptr */
404 slave_hw_ptr += dmix->slave_boundary;
405 diff = slave_hw_ptr - old_slave_hw_ptr;
407 dmix->hw_ptr += diff;
408 dmix->hw_ptr %= pcm->boundary;
409 if (pcm->stop_threshold >= pcm->boundary) /* don't care */
411 avail = snd_pcm_mmap_playback_avail(pcm);
412 if (avail > dmix->avail_max)
413 dmix->avail_max = avail;
414 if (avail >= pcm->stop_threshold) {
415 snd_timer_stop(dmix->timer);
416 gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type);
417 if (dmix->state == SND_PCM_STATE_RUNNING) {
418 dmix->state = SND_PCM_STATE_XRUN;
421 dmix->state = SND_PCM_STATE_SETUP;
422 /* clear queue to remove pending poll events */
423 snd_pcm_direct_clear_timer_queue(dmix);
428 static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm)
430 snd_pcm_direct_t *dmix = pcm->private_data;
433 switch (snd_pcm_state(dmix->spcm)) {
434 case SND_PCM_STATE_DISCONNECTED:
435 dmix->state = SND_PCM_STATE_DISCONNECTED;
437 case SND_PCM_STATE_XRUN:
438 if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
444 if (snd_pcm_direct_client_chk_xrun(dmix, pcm))
447 snd_pcm_hwsync(dmix->spcm);
449 return snd_pcm_dmix_sync_ptr0(pcm, *dmix->spcm->hw.ptr);
453 * plugin implementation
456 static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
458 snd_pcm_direct_t *dmix = pcm->private_data;
460 snd_pcm_state_t state;
461 state = snd_pcm_state(dmix->spcm);
463 case SND_PCM_STATE_SUSPENDED:
464 case SND_PCM_STATE_DISCONNECTED:
467 case SND_PCM_STATE_XRUN:
468 if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
474 snd_pcm_direct_client_chk_xrun(dmix, pcm);
475 if (dmix->state == STATE_RUN_PENDING)
476 return SNDRV_PCM_STATE_RUNNING;
480 static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
482 snd_pcm_direct_t *dmix = pcm->private_data;
484 memset(status, 0, sizeof(*status));
485 snd_pcm_status(dmix->spcm, status);
487 switch (dmix->state) {
488 case SNDRV_PCM_STATE_DRAINING:
489 case SNDRV_PCM_STATE_RUNNING:
490 snd_pcm_dmix_sync_ptr0(pcm, status->hw_ptr);
491 status->delay += snd_pcm_mmap_playback_delay(pcm)
492 + status->avail - dmix->spcm->buffer_size;
498 status->state = snd_pcm_dmix_state(pcm);
499 status->trigger_tstamp = dmix->trigger_tstamp;
500 status->avail = snd_pcm_mmap_playback_avail(pcm);
501 status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max;
506 static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
508 snd_pcm_direct_t *dmix = pcm->private_data;
511 switch(dmix->state) {
512 case SNDRV_PCM_STATE_DRAINING:
513 case SNDRV_PCM_STATE_RUNNING:
514 err = snd_pcm_dmix_sync_ptr(pcm);
518 case SNDRV_PCM_STATE_PREPARED:
519 case SNDRV_PCM_STATE_SUSPENDED:
520 case STATE_RUN_PENDING:
521 *delayp = snd_pcm_mmap_playback_hw_avail(pcm);
523 case SNDRV_PCM_STATE_XRUN:
525 case SNDRV_PCM_STATE_DISCONNECTED:
532 static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm)
534 snd_pcm_direct_t *dmix = pcm->private_data;
536 switch(dmix->state) {
537 case SNDRV_PCM_STATE_DRAINING:
538 case SNDRV_PCM_STATE_RUNNING:
540 return snd_pcm_dmix_sync_ptr(pcm);
541 case SNDRV_PCM_STATE_PREPARED:
542 case SNDRV_PCM_STATE_SUSPENDED:
543 case STATE_RUN_PENDING:
545 case SNDRV_PCM_STATE_XRUN:
547 case SNDRV_PCM_STATE_DISCONNECTED:
554 static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
556 snd_pcm_direct_t *dmix = pcm->private_data;
557 dmix->hw_ptr %= pcm->period_size;
558 dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr;
559 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
560 snd_pcm_direct_reset_slave_ptr(pcm, dmix);
564 static int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix)
568 snd_pcm_hwsync(dmix->spcm);
569 dmix->slave_appl_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr;
570 snd_pcm_direct_reset_slave_ptr(pcm, dmix);
571 err = snd_timer_start(dmix->timer);
574 dmix->state = SND_PCM_STATE_RUNNING;
578 static int snd_pcm_dmix_start(snd_pcm_t *pcm)
580 snd_pcm_direct_t *dmix = pcm->private_data;
581 snd_pcm_sframes_t avail;
584 if (dmix->state != SND_PCM_STATE_PREPARED)
586 avail = snd_pcm_mmap_playback_hw_avail(pcm);
588 dmix->state = STATE_RUN_PENDING;
592 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
594 snd_pcm_dmix_sync_area(pcm);
596 gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type);
600 static int snd_pcm_dmix_drop(snd_pcm_t *pcm)
602 snd_pcm_direct_t *dmix = pcm->private_data;
603 if (dmix->state == SND_PCM_STATE_OPEN)
605 dmix->state = SND_PCM_STATE_SETUP;
606 snd_pcm_direct_timer_stop(dmix);
611 static int __snd_pcm_dmix_drain(snd_pcm_t *pcm)
613 snd_pcm_direct_t *dmix = pcm->private_data;
614 snd_pcm_uframes_t stop_threshold;
617 switch (snd_pcm_state(dmix->spcm)) {
618 case SND_PCM_STATE_SUSPENDED:
624 if (dmix->state == SND_PCM_STATE_OPEN)
626 if (dmix->state == SND_PCM_STATE_PREPARED) {
627 if (snd_pcm_mmap_playback_hw_avail(pcm) > 0)
628 snd_pcm_dmix_start(pcm);
630 snd_pcm_dmix_drop(pcm);
635 if (dmix->state == SND_PCM_STATE_XRUN) {
636 snd_pcm_dmix_drop(pcm);
640 stop_threshold = pcm->stop_threshold;
641 if (pcm->stop_threshold > pcm->buffer_size)
642 pcm->stop_threshold = pcm->buffer_size;
643 dmix->state = SND_PCM_STATE_DRAINING;
645 err = snd_pcm_dmix_sync_ptr(pcm);
647 snd_pcm_dmix_drop(pcm);
650 if (dmix->state == SND_PCM_STATE_DRAINING) {
651 snd_pcm_dmix_sync_area(pcm);
652 if ((pcm->mode & SND_PCM_NONBLOCK) == 0) {
653 snd_pcm_wait_nocheck(pcm, -1);
654 snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */
657 switch (snd_pcm_state(dmix->spcm)) {
658 case SND_PCM_STATE_SUSPENDED:
665 if (pcm->mode & SND_PCM_NONBLOCK) {
666 if (dmix->state == SND_PCM_STATE_DRAINING) {
671 } while (dmix->state == SND_PCM_STATE_DRAINING);
673 pcm->stop_threshold = stop_threshold;
677 static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
682 err = __snd_pcm_dmix_drain(pcm);
687 static int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED)
692 static snd_pcm_sframes_t snd_pcm_dmix_rewindable(snd_pcm_t *pcm)
694 return snd_pcm_mmap_playback_hw_rewindable(pcm);
697 static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
699 snd_pcm_direct_t *dmix = pcm->private_data;
700 snd_pcm_uframes_t slave_appl_ptr, slave_size;
701 snd_pcm_uframes_t appl_ptr, size, transfer, result, frames_to_remix;
703 const snd_pcm_channel_area_t *src_areas, *dst_areas;
705 if (dmix->state == SND_PCM_STATE_RUNNING ||
706 dmix->state == SND_PCM_STATE_DRAINING) {
707 err = snd_pcm_dmix_hwsync(pcm);
712 /* (appl_ptr - last_appl_ptr) indicates the frames which are not
714 * (last_appl_ptr - hw_ptr) indicates the frames which are already
715 * mixed but not played yet.
716 * So they can be remixed.
719 size = pcm_frame_diff(dmix->last_appl_ptr, dmix->appl_ptr, pcm->boundary);
722 snd_pcm_mmap_appl_backward(pcm, size);
728 /* Always at this point last_appl_ptr == appl_ptr
729 * So (appl_ptr - hw_ptr) indicates the frames which can be remixed
731 size = pcm_frame_diff(dmix->appl_ptr, dmix->hw_ptr, pcm->boundary);
734 slave_size = pcm_frame_diff(dmix->slave_appl_ptr, dmix->slave_hw_ptr, pcm->boundary);
735 if (slave_size < size)
738 /* frames which should be remixed will be saved
739 * to also backward the appl pointer on success
741 frames_to_remix = size;
743 /* add sample areas here */
744 src_areas = snd_pcm_mmap_areas(pcm);
745 dst_areas = snd_pcm_mmap_areas(dmix->spcm);
746 dmix->last_appl_ptr -= size;
747 dmix->last_appl_ptr %= pcm->boundary;
748 appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
749 dmix->slave_appl_ptr -= size;
750 dmix->slave_appl_ptr %= dmix->slave_boundary;
751 slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
755 if (appl_ptr + transfer > pcm->buffer_size)
756 transfer = pcm->buffer_size - appl_ptr;
757 if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
758 transfer = dmix->slave_buffer_size - slave_appl_ptr;
759 remix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
763 slave_appl_ptr += transfer;
764 slave_appl_ptr %= dmix->slave_buffer_size;
765 appl_ptr += transfer;
766 appl_ptr %= pcm->buffer_size;
770 snd_pcm_mmap_appl_backward(pcm, frames_to_remix);
771 result += frames_to_remix;
772 /* At this point last_appl_ptr and appl_ptr has to indicate the
773 * position of the first not mixed frame
779 static snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm)
781 return snd_pcm_mmap_avail(pcm);
784 static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
786 snd_pcm_sframes_t avail;
788 avail = snd_pcm_dmix_forwardable(pcm);
789 if (frames > (snd_pcm_uframes_t)avail)
791 snd_pcm_mmap_appl_forward(pcm, frames);
795 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)
800 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)
805 static int snd_pcm_dmix_close(snd_pcm_t *pcm)
807 snd_pcm_direct_t *dmix = pcm->private_data;
810 snd_timer_close(dmix->timer);
811 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
812 snd_pcm_close(dmix->spcm);
814 snd_pcm_direct_server_discard(dmix);
816 snd_pcm_direct_client_discard(dmix);
817 shm_sum_discard(dmix);
818 if (snd_pcm_direct_shm_discard(dmix)) {
819 if (snd_pcm_direct_semaphore_discard(dmix))
820 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
822 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
823 free(dmix->bindings);
824 pcm->private_data = NULL;
829 static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
830 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
831 snd_pcm_uframes_t size)
833 snd_pcm_direct_t *dmix = pcm->private_data;
836 switch (snd_pcm_state(dmix->spcm)) {
837 case SND_PCM_STATE_XRUN:
838 if ((err = snd_pcm_direct_slave_recover(dmix)) < 0)
841 case SND_PCM_STATE_SUSPENDED:
846 if (snd_pcm_direct_client_chk_xrun(dmix, pcm))
850 snd_pcm_mmap_appl_forward(pcm, size);
851 if (dmix->state == STATE_RUN_PENDING) {
852 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
854 } else if (dmix->state == SND_PCM_STATE_RUNNING ||
855 dmix->state == SND_PCM_STATE_DRAINING) {
856 if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0)
859 if (dmix->state == SND_PCM_STATE_RUNNING ||
860 dmix->state == SND_PCM_STATE_DRAINING) {
861 /* ok, we commit the changes after the validation of area */
862 /* it's intended, although the result might be crappy */
863 snd_pcm_dmix_sync_area(pcm);
864 /* clear timer queue to avoid a bogus return from poll */
865 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
866 snd_pcm_direct_clear_timer_queue(dmix);
871 static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm)
873 snd_pcm_direct_t *dmix = pcm->private_data;
876 if (dmix->state == SND_PCM_STATE_RUNNING ||
877 dmix->state == SND_PCM_STATE_DRAINING) {
878 if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0)
881 if (dmix->state == SND_PCM_STATE_XRUN)
884 return snd_pcm_mmap_playback_avail(pcm);
887 static int snd_pcm_dmix_htimestamp(snd_pcm_t *pcm,
888 snd_pcm_uframes_t *avail,
889 snd_htimestamp_t *tstamp)
891 snd_pcm_direct_t *dmix = pcm->private_data;
892 snd_pcm_uframes_t avail1;
896 if (dmix->state == SND_PCM_STATE_RUNNING ||
897 dmix->state == SND_PCM_STATE_DRAINING)
898 snd_pcm_dmix_sync_ptr(pcm);
899 avail1 = snd_pcm_mmap_playback_avail(pcm);
900 if (ok && *avail == avail1)
903 *tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
909 static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
911 snd_pcm_direct_t *dmix = pcm->private_data;
912 if (dmix->state == SND_PCM_STATE_RUNNING)
913 snd_pcm_dmix_sync_area(pcm);
914 return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents);
918 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
920 snd_pcm_direct_t *dmix = pcm->private_data;
922 snd_output_printf(out, "Direct Stream Mixing PCM\n");
924 snd_output_printf(out, "Its setup is:\n");
925 snd_pcm_dump_setup(pcm, out);
928 snd_pcm_dump(dmix->spcm, out);
931 static const snd_pcm_ops_t snd_pcm_dmix_ops = {
932 .close = snd_pcm_dmix_close,
933 .info = snd_pcm_direct_info,
934 .hw_refine = snd_pcm_direct_hw_refine,
935 .hw_params = snd_pcm_direct_hw_params,
936 .hw_free = snd_pcm_direct_hw_free,
937 .sw_params = snd_pcm_direct_sw_params,
938 .channel_info = snd_pcm_direct_channel_info,
939 .dump = snd_pcm_dmix_dump,
940 .nonblock = snd_pcm_direct_nonblock,
941 .async = snd_pcm_direct_async,
942 .mmap = snd_pcm_direct_mmap,
943 .munmap = snd_pcm_direct_munmap,
944 .query_chmaps = snd_pcm_direct_query_chmaps,
945 .get_chmap = snd_pcm_direct_get_chmap,
946 .set_chmap = snd_pcm_direct_set_chmap,
949 static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
950 .status = snd_pcm_dmix_status,
951 .state = snd_pcm_dmix_state,
952 .hwsync = snd_pcm_dmix_hwsync,
953 .delay = snd_pcm_dmix_delay,
954 .prepare = snd_pcm_direct_prepare,
955 .reset = snd_pcm_dmix_reset,
956 .start = snd_pcm_dmix_start,
957 .drop = snd_pcm_dmix_drop,
958 .drain = snd_pcm_dmix_drain,
959 .pause = snd_pcm_dmix_pause,
960 .rewindable = snd_pcm_dmix_rewindable,
961 .rewind = snd_pcm_dmix_rewind,
962 .forwardable = snd_pcm_dmix_forwardable,
963 .forward = snd_pcm_dmix_forward,
964 .resume = snd_pcm_direct_resume,
968 .writei = snd_pcm_mmap_writei,
969 .writen = snd_pcm_mmap_writen,
970 .readi = snd_pcm_dmix_readi,
971 .readn = snd_pcm_dmix_readn,
972 .avail_update = snd_pcm_dmix_avail_update,
973 .mmap_commit = snd_pcm_dmix_mmap_commit,
974 .htimestamp = snd_pcm_dmix_htimestamp,
975 .poll_descriptors = snd_pcm_direct_poll_descriptors,
976 .poll_descriptors_count = NULL,
977 .poll_revents = snd_pcm_dmix_poll_revents,
981 * \brief Creates a new dmix PCM
982 * \param pcmp Returns created PCM handle
983 * \param name Name of PCM
984 * \param opts Direct PCM configurations
985 * \param params Parameters for slave
986 * \param root Configuration root
987 * \param sconf Slave configuration
988 * \param stream PCM Direction (stream)
989 * \param mode PCM Mode
990 * \retval zero on success otherwise a negative error code
991 * \warning Using of this function might be dangerous in the sense
992 * of compatibility reasons. The prototype might be freely
995 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
996 struct snd_pcm_direct_open_conf *opts,
997 struct slave_params *params,
998 snd_config_t *root, snd_config_t *sconf,
999 snd_pcm_stream_t stream, int mode)
1001 snd_pcm_t *pcm = NULL, *spcm = NULL;
1002 snd_pcm_direct_t *dmix = NULL;
1003 int ret, first_instance;
1004 int fail_sem_loop = 10;
1008 if (stream != SND_PCM_STREAM_PLAYBACK) {
1009 SNDERR("The dmix plugin supports only playback stream");
1013 dmix = calloc(1, sizeof(snd_pcm_direct_t));
1019 ret = snd_pcm_direct_parse_bindings(dmix, params, opts->bindings);
1023 dmix->ipc_key = opts->ipc_key;
1024 dmix->ipc_perm = opts->ipc_perm;
1025 dmix->ipc_gid = opts->ipc_gid;
1026 dmix->tstamp_type = opts->tstamp_type;
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->hw_ptr_alignment = opts->hw_ptr_alignment;
1065 dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
1066 dmix->direct_memory_access = opts->direct_memory_access;
1069 if (first_instance) {
1070 /* recursion is already checked in
1071 snd_pcm_direct_get_slave_ipc_offset() */
1072 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1073 mode | SND_PCM_NONBLOCK, NULL);
1075 SNDERR("unable to open slave");
1079 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1080 SNDERR("dmix plugin can be only connected to hw plugin");
1085 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
1087 SNDERR("unable to initialize slave");
1093 if (dmix->shmptr->use_server) {
1094 dmix->server_free = dmix_server_free;
1096 ret = snd_pcm_direct_server_create(dmix);
1098 SNDERR("unable to create server");
1103 dmix->shmptr->type = spcm->type;
1105 if (dmix->shmptr->use_server) {
1106 /* up semaphore to avoid deadlock */
1107 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1108 ret = snd_pcm_direct_client_connect(dmix);
1110 SNDERR("unable to connect client");
1114 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
1115 ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client");
1120 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1121 mode | SND_PCM_NONBLOCK |
1125 /* all other streams have been closed;
1126 * retry as the first instance
1128 if (ret == -EBADFD) {
1132 SNDERR("unable to open slave");
1135 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1136 SNDERR("dmix plugin can be only connected to hw plugin");
1141 ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params);
1143 SNDERR("unable to initialize slave");
1151 ret = shm_sum_create_or_connect(dmix);
1153 SNDERR("unable to initialize sum ring buffer");
1157 ret = snd_pcm_direct_initialize_poll_fd(dmix);
1159 SNDERR("unable to initialize poll_fd");
1163 mix_select_callbacks(dmix);
1165 pcm->poll_fd = dmix->poll_fd;
1166 pcm->poll_events = POLLIN; /* it's different than other plugins */
1167 pcm->tstamp_type = spcm->tstamp_type;
1169 snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
1170 snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
1172 if (dmix->channels == UINT_MAX)
1173 dmix->channels = dmix->shmptr->s.channels;
1175 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1182 snd_timer_close(dmix->timer);
1184 snd_pcm_direct_server_discard(dmix);
1186 snd_pcm_direct_client_discard(dmix);
1188 snd_pcm_close(spcm);
1189 if (dmix->u.dmix.shmid_sum >= 0)
1190 shm_sum_discard(dmix);
1191 if ((dmix->shmid >= 0) && (snd_pcm_direct_shm_discard(dmix))) {
1192 if (snd_pcm_direct_semaphore_discard(dmix))
1193 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
1195 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1198 free(dmix->bindings);
1206 /*! \page pcm_plugins
1208 \section pcm_plugins_dmix Plugin: dmix
1210 This plugin provides direct mixing of multiple streams. The resolution
1211 for 32-bit mixing is only 24-bit. The low significant byte is filled with
1212 zeros. The extra 8 bits are used for the saturation.
1216 type dmix # Direct mix
1217 ipc_key INT # unique IPC key
1218 ipc_key_add_uid BOOL # add current uid to unique IPC key
1219 ipc_perm INT # IPC permissions (octal, default 0600)
1220 hw_ptr_alignment STR # Slave application and hw pointer alignment type
1221 # STR can be one of the below strings :
1226 tstamp_type STR # timestamp type
1227 # STR can be one of the below strings :
1228 # default, gettimeofday, monotonic, monotonic_raw
1231 slave { # Slave definition
1232 pcm STR # slave PCM name
1234 pcm { } # slave PCM definition
1235 format STR # format definition
1236 rate INT # rate definition
1238 period_time INT # in usec
1240 period_size INT # in frames
1241 buffer_time INT # in usec
1243 buffer_size INT # in frames
1244 periods INT # when buffer_size or buffer_time is not specified
1246 bindings { # note: this is client independent!!!
1247 N INT # maps slave channel to client channel N
1249 slowptr BOOL # slow but more precise pointer updates
1253 <code>ipc_key</code> specfies the unique IPC key in integer.
1254 This number must be unique for each different dmix definition,
1255 since the shared memory is created with this key number.
1256 When <code>ipc_key_add_uid</code> is set true, the uid value is
1257 added to the value set in <code>ipc_key</code>. This will
1258 avoid the confliction of the same IPC key with different users
1261 <code>hw_ptr_alignment</code> specifies slave application and hw
1262 pointer alignment type. By default hw_ptr_alignment is auto. Below are
1263 the possible configurations:
1264 - no: minimal latency with minimal frames dropped at startup. But
1265 wakeup of application (return from snd_pcm_wait() or poll()) can
1266 take up to 2 * period.
1267 - roundup: It is guaranteed that all frames will be played at
1268 startup. But the latency will increase upto period-1 frames.
1269 - rounddown: It is guaranteed that a wakeup will happen for each
1270 period and frames can be written from application. But on startup
1271 upto period-1 frames will be dropped.
1272 - auto: Selects the best approach depending on the used period and
1274 If the application buffer size is < 2 * application period,
1275 "roundup" will be selected to avoid under runs. If the slave_period
1276 is < 10ms we could expect that there are low latency
1277 requirements. Therefore "rounddown" will be chosen to avoid long
1278 wakeup times. Such wakeup delay could otherwise end up with Xruns in
1279 case of a dependency to another sound device (e.g. forwarding of
1280 microphone to speaker). Else "no" will be chosen.
1282 Note that the dmix plugin itself supports only a single configuration.
1283 That is, it supports only the fixed rate (default 48000), format
1284 (\c S16), channels (2), and period_time (125000).
1285 For using other configuration, you have to set the value explicitly
1286 in the slave PCM definition. The rate, format and channels can be
1287 covered by an additional \ref pcm_plugins_dmix "plug plugin",
1288 but there is only one base configuration, anyway.
1290 An example configuration for setting 44100 Hz, \c S32_LE format
1291 as the slave PCM of "hw:0" is like below:
1295 ipc_key 321456 # any unique value
1296 ipc_key_add_uid true
1304 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
1307 % aplay -Dplug:dmix_44 foo_48k.wav
1310 For using the dmix plugin for OSS emulation device, you have to set
1311 the period and the buffer sizes in power of two. For example,
1315 ipc_key 321456 # any unique value
1316 ipc_key_add_uid true
1320 period_size 1024 # must be power of 2
1321 buffer_size 8192 # ditto
1325 <code>period_time 0</code> must be set, too, for resetting the
1326 default value. In the case of soundcards with multi-channel IO,
1327 adding the bindings would help
1332 0 0 # map from 0 to 0
1333 1 1 # map from 1 to 1
1337 so that only the first two channels are used by dmix.
1338 Also, note that ICE1712 have the limited buffer size, 5513 frames
1339 (corresponding to 640 kB). In this case, reduce the buffer_size
1342 \subsection pcm_plugins_dmix_funcref Function reference
1345 <LI>snd_pcm_dmix_open()
1346 <LI>_snd_pcm_dmix_open()
1352 * \brief Creates a new dmix PCM
1353 * \param pcmp Returns created PCM handle
1354 * \param name Name of PCM
1355 * \param root Root configuration node
1356 * \param conf Configuration node with dmix PCM description
1357 * \param stream PCM Stream
1358 * \param mode PCM Mode
1359 * \warning Using of this function might be dangerous in the sense
1360 * of compatibility reasons. The prototype might be freely
1361 * changed in future.
1363 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
1364 snd_config_t *root, snd_config_t *conf,
1365 snd_pcm_stream_t stream, int mode)
1367 snd_config_t *sconf;
1368 struct slave_params params;
1369 struct snd_pcm_direct_open_conf dopen;
1373 err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
1377 /* the default settings, it might be invalid for some hardware */
1378 params.format = SND_PCM_FORMAT_S16;
1379 params.rate = 48000;
1380 params.channels = 2;
1381 params.period_time = -1;
1382 params.buffer_time = -1;
1386 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
1387 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format,
1388 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
1389 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
1390 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
1391 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
1392 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1393 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1394 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
1398 /* set a reasonable default */
1399 if (psize == -1 && params.period_time == -1)
1400 params.period_time = 125000; /* 0.125 seconds */
1402 if (params.format == -2)
1403 params.format = SND_PCM_FORMAT_UNKNOWN;
1404 else if (!(dmix_supported_format & (1ULL << params.format))) {
1405 /* sorry, limited features */
1406 SNDERR("Unsupported format");
1407 snd_config_delete(sconf);
1411 params.period_size = psize;
1412 params.buffer_size = bsize;
1414 err = snd_pcm_dmix_open(pcmp, name, &dopen, ¶ms,
1415 root, sconf, stream, mode);
1416 snd_config_delete(sconf);
1420 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);