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->tstamp_type);
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->tstamp_type);
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->tstamp_type);
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_playback_hw_rewindable(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;
673 const snd_pcm_channel_area_t *src_areas, *dst_areas;
675 if (dmix->state == SND_PCM_STATE_RUNNING ||
676 dmix->state == SND_PCM_STATE_DRAINING) {
677 err = snd_pcm_dmix_hwsync(pcm);
682 if (dmix->last_appl_ptr < dmix->appl_ptr)
683 size = dmix->appl_ptr - dmix->last_appl_ptr;
685 size = dmix->appl_ptr + (pcm->boundary - dmix->last_appl_ptr);
688 snd_pcm_mmap_appl_backward(pcm, size);
694 if (dmix->hw_ptr < dmix->appl_ptr)
695 size = dmix->appl_ptr - dmix->hw_ptr;
697 size = dmix->appl_ptr + (pcm->boundary - dmix->hw_ptr);
700 if (dmix->slave_hw_ptr < dmix->slave_appl_ptr)
701 slave_size = dmix->slave_appl_ptr - dmix->slave_hw_ptr;
703 slave_size = dmix->slave_appl_ptr + (pcm->boundary - dmix->slave_hw_ptr);
704 if (slave_size < size)
709 /* add sample areas here */
710 src_areas = snd_pcm_mmap_areas(pcm);
711 dst_areas = snd_pcm_mmap_areas(dmix->spcm);
712 dmix->last_appl_ptr -= size;
713 dmix->last_appl_ptr %= pcm->boundary;
714 appl_ptr = dmix->last_appl_ptr % pcm->buffer_size;
715 dmix->slave_appl_ptr -= size;
716 dmix->slave_appl_ptr %= dmix->slave_boundary;
717 slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size;
721 if (appl_ptr + transfer > pcm->buffer_size)
722 transfer = pcm->buffer_size - appl_ptr;
723 if (slave_appl_ptr + transfer > dmix->slave_buffer_size)
724 transfer = dmix->slave_buffer_size - slave_appl_ptr;
725 remix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer);
729 slave_appl_ptr += transfer;
730 slave_appl_ptr %= dmix->slave_buffer_size;
731 appl_ptr += transfer;
732 appl_ptr %= pcm->buffer_size;
734 dmix->last_appl_ptr -= frames;
735 dmix->last_appl_ptr %= pcm->boundary;
736 dmix->slave_appl_ptr -= frames;
737 dmix->slave_appl_ptr %= dmix->slave_boundary;
740 snd_pcm_mmap_appl_backward(pcm, frames);
742 return result + frames;
745 static snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm)
747 return snd_pcm_mmap_avail(pcm);
750 static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames)
752 snd_pcm_sframes_t avail;
754 avail = snd_pcm_dmix_forwardable(pcm);
755 if (frames > (snd_pcm_uframes_t)avail)
757 snd_pcm_mmap_appl_forward(pcm, frames);
761 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)
766 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)
771 static int snd_pcm_dmix_close(snd_pcm_t *pcm)
773 snd_pcm_direct_t *dmix = pcm->private_data;
776 snd_timer_close(dmix->timer);
777 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
778 snd_pcm_close(dmix->spcm);
780 snd_pcm_direct_server_discard(dmix);
782 snd_pcm_direct_client_discard(dmix);
783 shm_sum_discard(dmix);
784 if (snd_pcm_direct_shm_discard(dmix)) {
785 if (snd_pcm_direct_semaphore_discard(dmix))
786 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
788 snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT);
789 free(dmix->bindings);
790 pcm->private_data = NULL;
795 static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm,
796 snd_pcm_uframes_t offset ATTRIBUTE_UNUSED,
797 snd_pcm_uframes_t size)
799 snd_pcm_direct_t *dmix = pcm->private_data;
802 switch (snd_pcm_state(dmix->spcm)) {
803 case SND_PCM_STATE_XRUN:
805 case SND_PCM_STATE_SUSPENDED:
812 snd_pcm_mmap_appl_forward(pcm, size);
813 if (dmix->state == STATE_RUN_PENDING) {
814 if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0)
816 } else if (dmix->state == SND_PCM_STATE_RUNNING ||
817 dmix->state == SND_PCM_STATE_DRAINING)
818 snd_pcm_dmix_sync_ptr(pcm);
819 if (dmix->state == SND_PCM_STATE_RUNNING ||
820 dmix->state == SND_PCM_STATE_DRAINING) {
821 /* ok, we commit the changes after the validation of area */
822 /* it's intended, although the result might be crappy */
823 snd_pcm_dmix_sync_area(pcm);
824 /* clear timer queue to avoid a bogus return from poll */
825 if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min)
826 snd_pcm_direct_clear_timer_queue(dmix);
831 static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm)
833 snd_pcm_direct_t *dmix = pcm->private_data;
835 if (dmix->state == SND_PCM_STATE_RUNNING ||
836 dmix->state == SND_PCM_STATE_DRAINING)
837 snd_pcm_dmix_sync_ptr(pcm);
838 return snd_pcm_mmap_playback_avail(pcm);
841 static int snd_pcm_dmix_htimestamp(snd_pcm_t *pcm,
842 snd_pcm_uframes_t *avail,
843 snd_htimestamp_t *tstamp)
845 snd_pcm_direct_t *dmix = pcm->private_data;
846 snd_pcm_uframes_t avail1;
850 if (dmix->state == SND_PCM_STATE_RUNNING ||
851 dmix->state == SND_PCM_STATE_DRAINING)
852 snd_pcm_dmix_sync_ptr(pcm);
853 avail1 = snd_pcm_mmap_playback_avail(pcm);
854 if (ok && *avail == avail1)
857 *tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm);
863 static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
865 snd_pcm_direct_t *dmix = pcm->private_data;
866 if (dmix->state == SND_PCM_STATE_RUNNING)
867 snd_pcm_dmix_sync_area(pcm);
868 return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents);
872 static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out)
874 snd_pcm_direct_t *dmix = pcm->private_data;
876 snd_output_printf(out, "Direct Stream Mixing PCM\n");
878 snd_output_printf(out, "Its setup is:\n");
879 snd_pcm_dump_setup(pcm, out);
882 snd_pcm_dump(dmix->spcm, out);
885 static const snd_pcm_ops_t snd_pcm_dmix_ops = {
886 .close = snd_pcm_dmix_close,
887 .info = snd_pcm_direct_info,
888 .hw_refine = snd_pcm_direct_hw_refine,
889 .hw_params = snd_pcm_direct_hw_params,
890 .hw_free = snd_pcm_direct_hw_free,
891 .sw_params = snd_pcm_direct_sw_params,
892 .channel_info = snd_pcm_direct_channel_info,
893 .dump = snd_pcm_dmix_dump,
894 .nonblock = snd_pcm_direct_nonblock,
895 .async = snd_pcm_direct_async,
896 .mmap = snd_pcm_direct_mmap,
897 .munmap = snd_pcm_direct_munmap,
898 .query_chmaps = snd_pcm_direct_query_chmaps,
899 .get_chmap = snd_pcm_direct_get_chmap,
900 .set_chmap = snd_pcm_direct_set_chmap,
903 static const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
904 .status = snd_pcm_dmix_status,
905 .state = snd_pcm_dmix_state,
906 .hwsync = snd_pcm_dmix_hwsync,
907 .delay = snd_pcm_dmix_delay,
908 .prepare = snd_pcm_dmix_prepare,
909 .reset = snd_pcm_dmix_reset,
910 .start = snd_pcm_dmix_start,
911 .drop = snd_pcm_dmix_drop,
912 .drain = snd_pcm_dmix_drain,
913 .pause = snd_pcm_dmix_pause,
914 .rewindable = snd_pcm_dmix_rewindable,
915 .rewind = snd_pcm_dmix_rewind,
916 .forwardable = snd_pcm_dmix_forwardable,
917 .forward = snd_pcm_dmix_forward,
918 .resume = snd_pcm_direct_resume,
922 .writei = snd_pcm_mmap_writei,
923 .writen = snd_pcm_mmap_writen,
924 .readi = snd_pcm_dmix_readi,
925 .readn = snd_pcm_dmix_readn,
926 .avail_update = snd_pcm_dmix_avail_update,
927 .mmap_commit = snd_pcm_dmix_mmap_commit,
928 .htimestamp = snd_pcm_dmix_htimestamp,
929 .poll_descriptors = NULL,
930 .poll_descriptors_count = NULL,
931 .poll_revents = snd_pcm_dmix_poll_revents,
935 * \brief Creates a new dmix PCM
936 * \param pcmp Returns created PCM handle
937 * \param name Name of PCM
938 * \param opts Direct PCM configurations
939 * \param params Parameters for slave
940 * \param root Configuration root
941 * \param sconf Slave configuration
942 * \param stream PCM Direction (stream)
943 * \param mode PCM Mode
944 * \retval zero on success otherwise a negative error code
945 * \warning Using of this function might be dangerous in the sense
946 * of compatibility reasons. The prototype might be freely
949 int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
950 struct snd_pcm_direct_open_conf *opts,
951 struct slave_params *params,
952 snd_config_t *root, snd_config_t *sconf,
953 snd_pcm_stream_t stream, int mode)
955 snd_pcm_t *pcm = NULL, *spcm = NULL;
956 snd_pcm_direct_t *dmix = NULL;
957 int ret, first_instance;
958 int fail_sem_loop = 10;
962 if (stream != SND_PCM_STREAM_PLAYBACK) {
963 SNDERR("The dmix plugin supports only playback stream");
967 dmix = calloc(1, sizeof(snd_pcm_direct_t));
973 ret = snd_pcm_direct_parse_bindings(dmix, params, opts->bindings);
977 dmix->ipc_key = opts->ipc_key;
978 dmix->ipc_perm = opts->ipc_perm;
979 dmix->ipc_gid = opts->ipc_gid;
983 ret = snd_pcm_new(&pcm, dmix->type = SND_PCM_TYPE_DMIX, name, stream, mode);
989 ret = snd_pcm_direct_semaphore_create_or_connect(dmix);
991 SNDERR("unable to create IPC semaphore");
994 ret = snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
996 snd_pcm_direct_semaphore_discard(dmix);
997 if (--fail_sem_loop <= 0)
1004 first_instance = ret = snd_pcm_direct_shm_create_or_connect(dmix);
1006 SNDERR("unable to create IPC shm instance");
1010 pcm->ops = &snd_pcm_dmix_ops;
1011 pcm->fast_ops = &snd_pcm_dmix_fast_ops;
1012 pcm->private_data = dmix;
1013 dmix->state = SND_PCM_STATE_OPEN;
1014 dmix->slowptr = opts->slowptr;
1015 dmix->max_periods = opts->max_periods;
1016 dmix->sync_ptr = snd_pcm_dmix_sync_ptr;
1018 if (first_instance) {
1019 /* recursion is already checked in
1020 snd_pcm_direct_get_slave_ipc_offset() */
1021 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1022 mode | SND_PCM_NONBLOCK, NULL);
1024 SNDERR("unable to open slave");
1028 if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) {
1029 SNDERR("dmix plugin can be only connected to hw plugin");
1034 ret = snd_pcm_direct_initialize_slave(dmix, spcm, params);
1036 SNDERR("unable to initialize slave");
1042 if (dmix->shmptr->use_server) {
1043 dmix->server_free = dmix_server_free;
1045 ret = snd_pcm_direct_server_create(dmix);
1047 SNDERR("unable to create server");
1052 dmix->shmptr->type = spcm->type;
1054 if (dmix->shmptr->use_server) {
1055 /* up semaphore to avoid deadlock */
1056 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1057 ret = snd_pcm_direct_client_connect(dmix);
1059 SNDERR("unable to connect client");
1063 snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
1064 ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client");
1069 ret = snd_pcm_open_slave(&spcm, root, sconf, stream,
1070 mode | SND_PCM_NONBLOCK |
1074 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_secondary_slave(dmix, spcm, params);
1085 SNDERR("unable to initialize slave");
1093 ret = shm_sum_create_or_connect(dmix);
1095 SNDERR("unable to initialize sum ring buffer");
1099 ret = snd_pcm_direct_initialize_poll_fd(dmix);
1101 SNDERR("unable to initialize poll_fd");
1105 mix_select_callbacks(dmix);
1107 pcm->poll_fd = dmix->poll_fd;
1108 pcm->poll_events = POLLIN; /* it's different than other plugins */
1109 pcm->tstamp_type = spcm->tstamp_type;
1111 snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
1112 snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
1114 if (dmix->channels == UINT_MAX)
1115 dmix->channels = dmix->shmptr->s.channels;
1117 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1124 snd_timer_close(dmix->timer);
1126 snd_pcm_direct_server_discard(dmix);
1128 snd_pcm_direct_client_discard(dmix);
1130 snd_pcm_close(spcm);
1131 if (dmix->u.dmix.shmid_sum >= 0)
1132 shm_sum_discard(dmix);
1133 if (dmix->shmid >= 0)
1134 snd_pcm_direct_shm_discard(dmix);
1135 if (snd_pcm_direct_semaphore_discard(dmix) < 0)
1136 snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
1139 free(dmix->bindings);
1147 /*! \page pcm_plugins
1149 \section pcm_plugins_dmix Plugin: dmix
1151 This plugin provides direct mixing of multiple streams. The resolution
1152 for 32-bit mixing is only 24-bit. The low significant byte is filled with
1153 zeros. The extra 8 bits are used for the saturation.
1157 type dmix # Direct mix
1158 ipc_key INT # unique IPC key
1159 ipc_key_add_uid BOOL # add current uid to unique IPC key
1160 ipc_perm INT # IPC permissions (octal, default 0600)
1163 slave { # Slave definition
1164 pcm STR # slave PCM name
1166 pcm { } # slave PCM definition
1167 format STR # format definition
1168 rate INT # rate definition
1170 period_time INT # in usec
1172 period_size INT # in bytes
1173 buffer_time INT # in usec
1175 buffer_size INT # in bytes
1176 periods INT # when buffer_size or buffer_time is not specified
1178 bindings { # note: this is client independent!!!
1179 N INT # maps slave channel to client channel N
1181 slowptr BOOL # slow but more precise pointer updates
1185 <code>ipc_key</code> specfies the unique IPC key in integer.
1186 This number must be unique for each different dmix definition,
1187 since the shared memory is created with this key number.
1188 When <code>ipc_key_add_uid</code> is set true, the uid value is
1189 added to the value set in <code>ipc_key</code>. This will
1190 avoid the confliction of the same IPC key with different users
1193 Note that the dmix plugin itself supports only a single configuration.
1194 That is, it supports only the fixed rate (default 48000), format
1195 (\c S16), channels (2), and period_time (125000).
1196 For using other configuration, you have to set the value explicitly
1197 in the slave PCM definition. The rate, format and channels can be
1198 covered by an additional \ref pcm_plugins_dmix "plug plugin",
1199 but there is only one base configuration, anyway.
1201 An example configuration for setting 44100 Hz, \c S32_LE format
1202 as the slave PCM of "hw:0" is like below:
1206 ipc_key 321456 # any unique value
1207 ipc_key_add_uid true
1215 You can hear 48000 Hz samples still using this dmix pcm via plug plugin
1218 % aplay -Dplug:dmix_44 foo_48k.wav
1221 For using the dmix plugin for OSS emulation device, you have to set
1222 the period and the buffer sizes in power of two. For example,
1226 ipc_key 321456 # any unique value
1227 ipc_key_add_uid true
1231 period_size 1024 # must be power of 2
1232 buffer_size 8192 # ditto
1236 <code>period_time 0</code> must be set, too, for resetting the
1237 default value. In the case of soundcards with multi-channel IO,
1238 adding the bindings would help
1243 0 0 # map from 0 to 0
1244 1 1 # map from 1 to 1
1248 so that only the first two channels are used by dmix.
1249 Also, note that ICE1712 have the limited buffer size, 5513 frames
1250 (corresponding to 640 kB). In this case, reduce the buffer_size
1253 \subsection pcm_plugins_dmix_funcref Function reference
1256 <LI>snd_pcm_dmix_open()
1257 <LI>_snd_pcm_dmix_open()
1263 * \brief Creates a new dmix PCM
1264 * \param pcmp Returns created PCM handle
1265 * \param name Name of PCM
1266 * \param root Root configuration node
1267 * \param conf Configuration node with dmix PCM description
1268 * \param stream PCM Stream
1269 * \param mode PCM Mode
1270 * \warning Using of this function might be dangerous in the sense
1271 * of compatibility reasons. The prototype might be freely
1272 * changed in future.
1274 int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
1275 snd_config_t *root, snd_config_t *conf,
1276 snd_pcm_stream_t stream, int mode)
1278 snd_config_t *sconf;
1279 struct slave_params params;
1280 struct snd_pcm_direct_open_conf dopen;
1284 err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen);
1288 /* the default settings, it might be invalid for some hardware */
1289 params.format = SND_PCM_FORMAT_S16;
1290 params.rate = 48000;
1291 params.channels = 2;
1292 params.period_time = -1;
1293 params.buffer_time = -1;
1297 err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8,
1298 SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format,
1299 SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
1300 SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
1301 SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
1302 SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
1303 SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
1304 SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
1305 SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
1309 /* set a reasonable default */
1310 if (psize == -1 && params.period_time == -1)
1311 params.period_time = 125000; /* 0.125 seconds */
1313 if (params.format == -2)
1314 params.format = SND_PCM_FORMAT_UNKNOWN;
1315 else if (!(dmix_supported_format & (1ULL << params.format))) {
1316 /* sorry, limited features */
1317 SNDERR("Unsupported format");
1318 snd_config_delete(sconf);
1322 params.period_size = psize;
1323 params.buffer_size = bsize;
1325 err = snd_pcm_dmix_open(pcmp, name, &dopen, ¶ms,
1326 root, sconf, stream, mode);
1327 snd_config_delete(sconf);
1331 SND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION);