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