1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_dmix.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM_Plugins 4d5ac70f0Sopenharmony_ci * \brief PCM Direct Stream Mixing (dmix) Plugin Interface 5d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 6d5ac70f0Sopenharmony_ci * \date 2003 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * PCM - Direct Stream Mixing 10d5ac70f0Sopenharmony_ci * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz> 11d5ac70f0Sopenharmony_ci * 12d5ac70f0Sopenharmony_ci * 13d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 14d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 15d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 16d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 17d5ac70f0Sopenharmony_ci * 18d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 19d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 20d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 22d5ac70f0Sopenharmony_ci * 23d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 24d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 25d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 26d5ac70f0Sopenharmony_ci * 27d5ac70f0Sopenharmony_ci */ 28d5ac70f0Sopenharmony_ci 29d5ac70f0Sopenharmony_ci#include "pcm_local.h" 30d5ac70f0Sopenharmony_ci#include <stdio.h> 31d5ac70f0Sopenharmony_ci#include <stdlib.h> 32d5ac70f0Sopenharmony_ci#include <stddef.h> 33d5ac70f0Sopenharmony_ci#include <unistd.h> 34d5ac70f0Sopenharmony_ci#include <signal.h> 35d5ac70f0Sopenharmony_ci#include <string.h> 36d5ac70f0Sopenharmony_ci#include <fcntl.h> 37d5ac70f0Sopenharmony_ci#include <ctype.h> 38d5ac70f0Sopenharmony_ci#include <grp.h> 39d5ac70f0Sopenharmony_ci#include <sys/ioctl.h> 40d5ac70f0Sopenharmony_ci#include <sys/mman.h> 41d5ac70f0Sopenharmony_ci#include <sys/shm.h> 42d5ac70f0Sopenharmony_ci#include <sys/sem.h> 43d5ac70f0Sopenharmony_ci#include <sys/wait.h> 44d5ac70f0Sopenharmony_ci#include <sys/socket.h> 45d5ac70f0Sopenharmony_ci#include <sys/un.h> 46d5ac70f0Sopenharmony_ci#include <sys/mman.h> 47d5ac70f0Sopenharmony_ci#include "pcm_direct.h" 48d5ac70f0Sopenharmony_ci 49d5ac70f0Sopenharmony_ci#ifndef PIC 50d5ac70f0Sopenharmony_ci/* entry for static linking */ 51d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_dmix = ""; 52d5ac70f0Sopenharmony_ci#endif 53d5ac70f0Sopenharmony_ci 54d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 55d5ac70f0Sopenharmony_ci/* start is pending - this state happens when rate plugin does a delayed commit */ 56d5ac70f0Sopenharmony_ci#define STATE_RUN_PENDING 1024 57d5ac70f0Sopenharmony_ci#endif 58d5ac70f0Sopenharmony_ci 59d5ac70f0Sopenharmony_ci/* 60d5ac70f0Sopenharmony_ci * 61d5ac70f0Sopenharmony_ci */ 62d5ac70f0Sopenharmony_ci 63d5ac70f0Sopenharmony_cistatic int shm_sum_discard(snd_pcm_direct_t *dmix); 64d5ac70f0Sopenharmony_ci 65d5ac70f0Sopenharmony_ci/* 66d5ac70f0Sopenharmony_ci * sum ring buffer shared memory area 67d5ac70f0Sopenharmony_ci */ 68d5ac70f0Sopenharmony_cistatic int shm_sum_create_or_connect(snd_pcm_direct_t *dmix) 69d5ac70f0Sopenharmony_ci{ 70d5ac70f0Sopenharmony_ci struct shmid_ds buf; 71d5ac70f0Sopenharmony_ci int tmpid, err; 72d5ac70f0Sopenharmony_ci size_t size; 73d5ac70f0Sopenharmony_ci 74d5ac70f0Sopenharmony_ci size = dmix->shmptr->s.channels * 75d5ac70f0Sopenharmony_ci dmix->shmptr->s.buffer_size * 76d5ac70f0Sopenharmony_ci sizeof(signed int); 77d5ac70f0Sopenharmony_ciretryshm: 78d5ac70f0Sopenharmony_ci dmix->u.dmix.shmid_sum = shmget(dmix->ipc_key + 1, size, 79d5ac70f0Sopenharmony_ci IPC_CREAT | dmix->ipc_perm); 80d5ac70f0Sopenharmony_ci err = -errno; 81d5ac70f0Sopenharmony_ci if (dmix->u.dmix.shmid_sum < 0) { 82d5ac70f0Sopenharmony_ci if (errno == EINVAL) 83d5ac70f0Sopenharmony_ci if ((tmpid = shmget(dmix->ipc_key + 1, 0, dmix->ipc_perm)) != -1) 84d5ac70f0Sopenharmony_ci if (!shmctl(tmpid, IPC_STAT, &buf)) 85d5ac70f0Sopenharmony_ci if (!buf.shm_nattch) 86d5ac70f0Sopenharmony_ci /* no users so destroy the segment */ 87d5ac70f0Sopenharmony_ci if (!shmctl(tmpid, IPC_RMID, NULL)) 88d5ac70f0Sopenharmony_ci goto retryshm; 89d5ac70f0Sopenharmony_ci return err; 90d5ac70f0Sopenharmony_ci } 91d5ac70f0Sopenharmony_ci if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0) { 92d5ac70f0Sopenharmony_ci err = -errno; 93d5ac70f0Sopenharmony_ci shm_sum_discard(dmix); 94d5ac70f0Sopenharmony_ci return err; 95d5ac70f0Sopenharmony_ci } 96d5ac70f0Sopenharmony_ci if (dmix->ipc_gid >= 0) { 97d5ac70f0Sopenharmony_ci buf.shm_perm.gid = dmix->ipc_gid; 98d5ac70f0Sopenharmony_ci shmctl(dmix->u.dmix.shmid_sum, IPC_SET, &buf); 99d5ac70f0Sopenharmony_ci } 100d5ac70f0Sopenharmony_ci dmix->u.dmix.sum_buffer = shmat(dmix->u.dmix.shmid_sum, 0, 0); 101d5ac70f0Sopenharmony_ci if (dmix->u.dmix.sum_buffer == (void *) -1) { 102d5ac70f0Sopenharmony_ci err = -errno; 103d5ac70f0Sopenharmony_ci shm_sum_discard(dmix); 104d5ac70f0Sopenharmony_ci return err; 105d5ac70f0Sopenharmony_ci } 106d5ac70f0Sopenharmony_ci mlock(dmix->u.dmix.sum_buffer, size); 107d5ac70f0Sopenharmony_ci return 0; 108d5ac70f0Sopenharmony_ci} 109d5ac70f0Sopenharmony_ci 110d5ac70f0Sopenharmony_cistatic int shm_sum_discard(snd_pcm_direct_t *dmix) 111d5ac70f0Sopenharmony_ci{ 112d5ac70f0Sopenharmony_ci struct shmid_ds buf; 113d5ac70f0Sopenharmony_ci int ret = 0; 114d5ac70f0Sopenharmony_ci 115d5ac70f0Sopenharmony_ci if (dmix->u.dmix.shmid_sum < 0) 116d5ac70f0Sopenharmony_ci return -EINVAL; 117d5ac70f0Sopenharmony_ci if (dmix->u.dmix.sum_buffer != (void *) -1 && shmdt(dmix->u.dmix.sum_buffer) < 0) 118d5ac70f0Sopenharmony_ci return -errno; 119d5ac70f0Sopenharmony_ci dmix->u.dmix.sum_buffer = (void *) -1; 120d5ac70f0Sopenharmony_ci if (shmctl(dmix->u.dmix.shmid_sum, IPC_STAT, &buf) < 0) 121d5ac70f0Sopenharmony_ci return -errno; 122d5ac70f0Sopenharmony_ci if (buf.shm_nattch == 0) { /* we're the last user, destroy the segment */ 123d5ac70f0Sopenharmony_ci if (shmctl(dmix->u.dmix.shmid_sum, IPC_RMID, NULL) < 0) 124d5ac70f0Sopenharmony_ci return -errno; 125d5ac70f0Sopenharmony_ci ret = 1; 126d5ac70f0Sopenharmony_ci } 127d5ac70f0Sopenharmony_ci dmix->u.dmix.shmid_sum = -1; 128d5ac70f0Sopenharmony_ci return ret; 129d5ac70f0Sopenharmony_ci} 130d5ac70f0Sopenharmony_ci 131d5ac70f0Sopenharmony_cistatic void dmix_server_free(snd_pcm_direct_t *dmix) 132d5ac70f0Sopenharmony_ci{ 133d5ac70f0Sopenharmony_ci /* remove the memory region */ 134d5ac70f0Sopenharmony_ci shm_sum_create_or_connect(dmix); 135d5ac70f0Sopenharmony_ci shm_sum_discard(dmix); 136d5ac70f0Sopenharmony_ci} 137d5ac70f0Sopenharmony_ci 138d5ac70f0Sopenharmony_ci/* 139d5ac70f0Sopenharmony_ci * the main function of this plugin: mixing 140d5ac70f0Sopenharmony_ci * FIXME: optimize it for different architectures 141d5ac70f0Sopenharmony_ci */ 142d5ac70f0Sopenharmony_ci 143d5ac70f0Sopenharmony_ci#include "pcm_dmix_generic.c" 144d5ac70f0Sopenharmony_ci#if defined(__i386__) 145d5ac70f0Sopenharmony_ci#include "pcm_dmix_i386.c" 146d5ac70f0Sopenharmony_ci#elif defined(__x86_64__) 147d5ac70f0Sopenharmony_ci#include "pcm_dmix_x86_64.c" 148d5ac70f0Sopenharmony_ci#else 149d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 150d5ac70f0Sopenharmony_ci#define mix_select_callbacks(x) generic_mix_select_callbacks(x) 151d5ac70f0Sopenharmony_ci#define dmix_supported_format generic_dmix_supported_format 152d5ac70f0Sopenharmony_ci#endif 153d5ac70f0Sopenharmony_ci#endif 154d5ac70f0Sopenharmony_ci 155d5ac70f0Sopenharmony_cistatic void mix_areas(snd_pcm_direct_t *dmix, 156d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, 157d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *dst_areas, 158d5ac70f0Sopenharmony_ci snd_pcm_uframes_t src_ofs, 159d5ac70f0Sopenharmony_ci snd_pcm_uframes_t dst_ofs, 160d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 161d5ac70f0Sopenharmony_ci{ 162d5ac70f0Sopenharmony_ci unsigned int src_step, dst_step; 163d5ac70f0Sopenharmony_ci unsigned int chn, dchn, channels, sample_size; 164d5ac70f0Sopenharmony_ci mix_areas_t *do_mix_areas; 165d5ac70f0Sopenharmony_ci 166d5ac70f0Sopenharmony_ci channels = dmix->channels; 167d5ac70f0Sopenharmony_ci switch (dmix->shmptr->s.format) { 168d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S16_LE: 169d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S16_BE: 170d5ac70f0Sopenharmony_ci sample_size = 2; 171d5ac70f0Sopenharmony_ci do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_16; 172d5ac70f0Sopenharmony_ci break; 173d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S32_LE: 174d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S32_BE: 175d5ac70f0Sopenharmony_ci sample_size = 4; 176d5ac70f0Sopenharmony_ci do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_32; 177d5ac70f0Sopenharmony_ci break; 178d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S24_LE: 179d5ac70f0Sopenharmony_ci sample_size = 4; 180d5ac70f0Sopenharmony_ci do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_24; 181d5ac70f0Sopenharmony_ci break; 182d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S24_3LE: 183d5ac70f0Sopenharmony_ci sample_size = 3; 184d5ac70f0Sopenharmony_ci do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_24; 185d5ac70f0Sopenharmony_ci break; 186d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_U8: 187d5ac70f0Sopenharmony_ci sample_size = 1; 188d5ac70f0Sopenharmony_ci do_mix_areas = (mix_areas_t *)dmix->u.dmix.mix_areas_u8; 189d5ac70f0Sopenharmony_ci break; 190d5ac70f0Sopenharmony_ci default: 191d5ac70f0Sopenharmony_ci return; 192d5ac70f0Sopenharmony_ci } 193d5ac70f0Sopenharmony_ci if (dmix->interleaved) { 194d5ac70f0Sopenharmony_ci /* 195d5ac70f0Sopenharmony_ci * process all areas in one loop 196d5ac70f0Sopenharmony_ci * it optimizes the memory accesses for this case 197d5ac70f0Sopenharmony_ci */ 198d5ac70f0Sopenharmony_ci do_mix_areas(size * channels, 199d5ac70f0Sopenharmony_ci (unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels, 200d5ac70f0Sopenharmony_ci (unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels, 201d5ac70f0Sopenharmony_ci dmix->u.dmix.sum_buffer + dst_ofs * channels, 202d5ac70f0Sopenharmony_ci sample_size, 203d5ac70f0Sopenharmony_ci sample_size, 204d5ac70f0Sopenharmony_ci sizeof(signed int)); 205d5ac70f0Sopenharmony_ci return; 206d5ac70f0Sopenharmony_ci } 207d5ac70f0Sopenharmony_ci for (chn = 0; chn < channels; chn++) { 208d5ac70f0Sopenharmony_ci dchn = dmix->bindings ? dmix->bindings[chn] : chn; 209d5ac70f0Sopenharmony_ci if (dchn >= dmix->shmptr->s.channels) 210d5ac70f0Sopenharmony_ci continue; 211d5ac70f0Sopenharmony_ci src_step = src_areas[chn].step / 8; 212d5ac70f0Sopenharmony_ci dst_step = dst_areas[dchn].step / 8; 213d5ac70f0Sopenharmony_ci do_mix_areas(size, 214d5ac70f0Sopenharmony_ci ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step, 215d5ac70f0Sopenharmony_ci ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step, 216d5ac70f0Sopenharmony_ci dmix->u.dmix.sum_buffer + dmix->shmptr->s.channels * dst_ofs + dchn, 217d5ac70f0Sopenharmony_ci dst_step, 218d5ac70f0Sopenharmony_ci src_step, 219d5ac70f0Sopenharmony_ci dmix->shmptr->s.channels * sizeof(signed int)); 220d5ac70f0Sopenharmony_ci } 221d5ac70f0Sopenharmony_ci} 222d5ac70f0Sopenharmony_ci 223d5ac70f0Sopenharmony_cistatic void remix_areas(snd_pcm_direct_t *dmix, 224d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, 225d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *dst_areas, 226d5ac70f0Sopenharmony_ci snd_pcm_uframes_t src_ofs, 227d5ac70f0Sopenharmony_ci snd_pcm_uframes_t dst_ofs, 228d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 229d5ac70f0Sopenharmony_ci{ 230d5ac70f0Sopenharmony_ci unsigned int src_step, dst_step; 231d5ac70f0Sopenharmony_ci unsigned int chn, dchn, channels, sample_size; 232d5ac70f0Sopenharmony_ci mix_areas_t *do_remix_areas; 233d5ac70f0Sopenharmony_ci 234d5ac70f0Sopenharmony_ci channels = dmix->channels; 235d5ac70f0Sopenharmony_ci switch (dmix->shmptr->s.format) { 236d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S16_LE: 237d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S16_BE: 238d5ac70f0Sopenharmony_ci sample_size = 2; 239d5ac70f0Sopenharmony_ci do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_16; 240d5ac70f0Sopenharmony_ci break; 241d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S32_LE: 242d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S32_BE: 243d5ac70f0Sopenharmony_ci sample_size = 4; 244d5ac70f0Sopenharmony_ci do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_32; 245d5ac70f0Sopenharmony_ci break; 246d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S24_LE: 247d5ac70f0Sopenharmony_ci sample_size = 4; 248d5ac70f0Sopenharmony_ci do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_24; 249d5ac70f0Sopenharmony_ci break; 250d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_S24_3LE: 251d5ac70f0Sopenharmony_ci sample_size = 3; 252d5ac70f0Sopenharmony_ci do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_24; 253d5ac70f0Sopenharmony_ci break; 254d5ac70f0Sopenharmony_ci case SND_PCM_FORMAT_U8: 255d5ac70f0Sopenharmony_ci sample_size = 1; 256d5ac70f0Sopenharmony_ci do_remix_areas = (mix_areas_t *)dmix->u.dmix.remix_areas_u8; 257d5ac70f0Sopenharmony_ci break; 258d5ac70f0Sopenharmony_ci default: 259d5ac70f0Sopenharmony_ci return; 260d5ac70f0Sopenharmony_ci } 261d5ac70f0Sopenharmony_ci if (dmix->interleaved) { 262d5ac70f0Sopenharmony_ci /* 263d5ac70f0Sopenharmony_ci * process all areas in one loop 264d5ac70f0Sopenharmony_ci * it optimizes the memory accesses for this case 265d5ac70f0Sopenharmony_ci */ 266d5ac70f0Sopenharmony_ci do_remix_areas(size * channels, 267d5ac70f0Sopenharmony_ci (unsigned char *)dst_areas[0].addr + sample_size * dst_ofs * channels, 268d5ac70f0Sopenharmony_ci (unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels, 269d5ac70f0Sopenharmony_ci dmix->u.dmix.sum_buffer + dst_ofs * channels, 270d5ac70f0Sopenharmony_ci sample_size, 271d5ac70f0Sopenharmony_ci sample_size, 272d5ac70f0Sopenharmony_ci sizeof(signed int)); 273d5ac70f0Sopenharmony_ci return; 274d5ac70f0Sopenharmony_ci } 275d5ac70f0Sopenharmony_ci for (chn = 0; chn < channels; chn++) { 276d5ac70f0Sopenharmony_ci dchn = dmix->bindings ? dmix->bindings[chn] : chn; 277d5ac70f0Sopenharmony_ci if (dchn >= dmix->shmptr->s.channels) 278d5ac70f0Sopenharmony_ci continue; 279d5ac70f0Sopenharmony_ci src_step = src_areas[chn].step / 8; 280d5ac70f0Sopenharmony_ci dst_step = dst_areas[dchn].step / 8; 281d5ac70f0Sopenharmony_ci do_remix_areas(size, 282d5ac70f0Sopenharmony_ci ((unsigned char *)dst_areas[dchn].addr + dst_areas[dchn].first / 8) + dst_ofs * dst_step, 283d5ac70f0Sopenharmony_ci ((unsigned char *)src_areas[chn].addr + src_areas[chn].first / 8) + src_ofs * src_step, 284d5ac70f0Sopenharmony_ci dmix->u.dmix.sum_buffer + dmix->shmptr->s.channels * dst_ofs + dchn, 285d5ac70f0Sopenharmony_ci dst_step, 286d5ac70f0Sopenharmony_ci src_step, 287d5ac70f0Sopenharmony_ci dmix->shmptr->s.channels * sizeof(signed int)); 288d5ac70f0Sopenharmony_ci } 289d5ac70f0Sopenharmony_ci} 290d5ac70f0Sopenharmony_ci 291d5ac70f0Sopenharmony_ci/* 292d5ac70f0Sopenharmony_ci * if no concurrent access is allowed in the mixing routines, we need to protect 293d5ac70f0Sopenharmony_ci * the area via semaphore 294d5ac70f0Sopenharmony_ci */ 295d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 296d5ac70f0Sopenharmony_cistatic void dmix_down_sem(snd_pcm_direct_t *dmix) 297d5ac70f0Sopenharmony_ci{ 298d5ac70f0Sopenharmony_ci if (dmix->u.dmix.use_sem) 299d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); 300d5ac70f0Sopenharmony_ci} 301d5ac70f0Sopenharmony_ci 302d5ac70f0Sopenharmony_cistatic void dmix_up_sem(snd_pcm_direct_t *dmix) 303d5ac70f0Sopenharmony_ci{ 304d5ac70f0Sopenharmony_ci if (dmix->u.dmix.use_sem) 305d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); 306d5ac70f0Sopenharmony_ci} 307d5ac70f0Sopenharmony_ci#endif 308d5ac70f0Sopenharmony_ci 309d5ac70f0Sopenharmony_ci/* 310d5ac70f0Sopenharmony_ci * synchronize shm ring buffer with hardware 311d5ac70f0Sopenharmony_ci */ 312d5ac70f0Sopenharmony_cistatic void snd_pcm_dmix_sync_area(snd_pcm_t *pcm) 313d5ac70f0Sopenharmony_ci{ 314d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 315d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size; 316d5ac70f0Sopenharmony_ci snd_pcm_uframes_t appl_ptr, size, transfer; 317d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, *dst_areas; 318d5ac70f0Sopenharmony_ci 319d5ac70f0Sopenharmony_ci /* calculate the size to transfer */ 320d5ac70f0Sopenharmony_ci /* check the available size in the local buffer 321d5ac70f0Sopenharmony_ci * last_appl_ptr keeps the last updated position 322d5ac70f0Sopenharmony_ci */ 323d5ac70f0Sopenharmony_ci size = pcm_frame_diff2(dmix->appl_ptr, dmix->last_appl_ptr, pcm->boundary); 324d5ac70f0Sopenharmony_ci if (! size) 325d5ac70f0Sopenharmony_ci return; 326d5ac70f0Sopenharmony_ci 327d5ac70f0Sopenharmony_ci /* the slave_app_ptr can be far behind the slave_hw_ptr */ 328d5ac70f0Sopenharmony_ci /* reduce mixing and errors here - just skip not catched writes */ 329d5ac70f0Sopenharmony_ci slave_size = pcm_frame_diff(dmix->slave_appl_ptr, dmix->slave_hw_ptr, dmix->slave_boundary); 330d5ac70f0Sopenharmony_ci if (slave_size > dmix->slave_buffer_size) { 331d5ac70f0Sopenharmony_ci transfer = dmix->slave_buffer_size - slave_size; 332d5ac70f0Sopenharmony_ci if (transfer > size) 333d5ac70f0Sopenharmony_ci transfer = size; 334d5ac70f0Sopenharmony_ci dmix->last_appl_ptr += transfer; 335d5ac70f0Sopenharmony_ci dmix->last_appl_ptr %= pcm->boundary; 336d5ac70f0Sopenharmony_ci dmix->slave_appl_ptr += transfer; 337d5ac70f0Sopenharmony_ci dmix->slave_appl_ptr %= dmix->slave_boundary; 338d5ac70f0Sopenharmony_ci size = pcm_frame_diff2(dmix->appl_ptr, dmix->last_appl_ptr, pcm->boundary); 339d5ac70f0Sopenharmony_ci if (! size) 340d5ac70f0Sopenharmony_ci return; 341d5ac70f0Sopenharmony_ci } 342d5ac70f0Sopenharmony_ci 343d5ac70f0Sopenharmony_ci /* check the available size in the slave PCM buffer */ 344d5ac70f0Sopenharmony_ci slave_hw_ptr = dmix->slave_hw_ptr; 345d5ac70f0Sopenharmony_ci /* don't write on the last active period - this area may be cleared 346d5ac70f0Sopenharmony_ci * by the driver during mix operation... 347d5ac70f0Sopenharmony_ci */ 348d5ac70f0Sopenharmony_ci slave_hw_ptr -= slave_hw_ptr % dmix->slave_period_size; 349d5ac70f0Sopenharmony_ci slave_hw_ptr += dmix->slave_buffer_size; 350d5ac70f0Sopenharmony_ci if (slave_hw_ptr >= dmix->slave_boundary) 351d5ac70f0Sopenharmony_ci slave_hw_ptr -= dmix->slave_boundary; 352d5ac70f0Sopenharmony_ci slave_size = pcm_frame_diff(slave_hw_ptr, dmix->slave_appl_ptr, dmix->slave_boundary); 353d5ac70f0Sopenharmony_ci if (slave_size < size) 354d5ac70f0Sopenharmony_ci size = slave_size; 355d5ac70f0Sopenharmony_ci if (! size) 356d5ac70f0Sopenharmony_ci return; 357d5ac70f0Sopenharmony_ci 358d5ac70f0Sopenharmony_ci /* add sample areas here */ 359d5ac70f0Sopenharmony_ci src_areas = snd_pcm_mmap_areas(pcm); 360d5ac70f0Sopenharmony_ci dst_areas = snd_pcm_mmap_areas(dmix->spcm); 361d5ac70f0Sopenharmony_ci appl_ptr = dmix->last_appl_ptr % pcm->buffer_size; 362d5ac70f0Sopenharmony_ci dmix->last_appl_ptr += size; 363d5ac70f0Sopenharmony_ci dmix->last_appl_ptr %= pcm->boundary; 364d5ac70f0Sopenharmony_ci slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size; 365d5ac70f0Sopenharmony_ci dmix->slave_appl_ptr += size; 366d5ac70f0Sopenharmony_ci dmix->slave_appl_ptr %= dmix->slave_boundary; 367d5ac70f0Sopenharmony_ci dmix_down_sem(dmix); 368d5ac70f0Sopenharmony_ci for (;;) { 369d5ac70f0Sopenharmony_ci transfer = size; 370d5ac70f0Sopenharmony_ci if (appl_ptr + transfer > pcm->buffer_size) 371d5ac70f0Sopenharmony_ci transfer = pcm->buffer_size - appl_ptr; 372d5ac70f0Sopenharmony_ci if (slave_appl_ptr + transfer > dmix->slave_buffer_size) 373d5ac70f0Sopenharmony_ci transfer = dmix->slave_buffer_size - slave_appl_ptr; 374d5ac70f0Sopenharmony_ci mix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); 375d5ac70f0Sopenharmony_ci size -= transfer; 376d5ac70f0Sopenharmony_ci if (! size) 377d5ac70f0Sopenharmony_ci break; 378d5ac70f0Sopenharmony_ci slave_appl_ptr += transfer; 379d5ac70f0Sopenharmony_ci slave_appl_ptr %= dmix->slave_buffer_size; 380d5ac70f0Sopenharmony_ci appl_ptr += transfer; 381d5ac70f0Sopenharmony_ci appl_ptr %= pcm->buffer_size; 382d5ac70f0Sopenharmony_ci } 383d5ac70f0Sopenharmony_ci dmix_up_sem(dmix); 384d5ac70f0Sopenharmony_ci} 385d5ac70f0Sopenharmony_ci 386d5ac70f0Sopenharmony_ci/* 387d5ac70f0Sopenharmony_ci * synchronize hardware pointer (hw_ptr) with ours 388d5ac70f0Sopenharmony_ci */ 389d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr) 390d5ac70f0Sopenharmony_ci{ 391d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 392d5ac70f0Sopenharmony_ci snd_pcm_uframes_t old_slave_hw_ptr, avail; 393d5ac70f0Sopenharmony_ci snd_pcm_sframes_t diff; 394d5ac70f0Sopenharmony_ci 395d5ac70f0Sopenharmony_ci old_slave_hw_ptr = dmix->slave_hw_ptr; 396d5ac70f0Sopenharmony_ci dmix->slave_hw_ptr = slave_hw_ptr; 397d5ac70f0Sopenharmony_ci diff = pcm_frame_diff(slave_hw_ptr, old_slave_hw_ptr, dmix->slave_boundary); 398d5ac70f0Sopenharmony_ci if (diff == 0) /* fast path */ 399d5ac70f0Sopenharmony_ci return 0; 400d5ac70f0Sopenharmony_ci if (dmix->state != SND_PCM_STATE_RUNNING && 401d5ac70f0Sopenharmony_ci dmix->state != SND_PCM_STATE_DRAINING) 402d5ac70f0Sopenharmony_ci /* not really started yet - don't update hw_ptr */ 403d5ac70f0Sopenharmony_ci return 0; 404d5ac70f0Sopenharmony_ci dmix->hw_ptr += diff; 405d5ac70f0Sopenharmony_ci dmix->hw_ptr %= pcm->boundary; 406d5ac70f0Sopenharmony_ci if (pcm->stop_threshold >= pcm->boundary) /* don't care */ 407d5ac70f0Sopenharmony_ci return 0; 408d5ac70f0Sopenharmony_ci avail = snd_pcm_mmap_playback_avail(pcm); 409d5ac70f0Sopenharmony_ci if (avail > dmix->avail_max) 410d5ac70f0Sopenharmony_ci dmix->avail_max = avail; 411d5ac70f0Sopenharmony_ci if (avail >= pcm->stop_threshold) { 412d5ac70f0Sopenharmony_ci snd_timer_stop(dmix->timer); 413d5ac70f0Sopenharmony_ci gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type); 414d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_RUNNING) { 415d5ac70f0Sopenharmony_ci dmix->state = SND_PCM_STATE_XRUN; 416d5ac70f0Sopenharmony_ci return -EPIPE; 417d5ac70f0Sopenharmony_ci } 418d5ac70f0Sopenharmony_ci dmix->state = SND_PCM_STATE_SETUP; 419d5ac70f0Sopenharmony_ci /* clear queue to remove pending poll events */ 420d5ac70f0Sopenharmony_ci snd_pcm_direct_clear_timer_queue(dmix); 421d5ac70f0Sopenharmony_ci } 422d5ac70f0Sopenharmony_ci return 0; 423d5ac70f0Sopenharmony_ci} 424d5ac70f0Sopenharmony_ci 425d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) 426d5ac70f0Sopenharmony_ci{ 427d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 428d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_hw_ptr; 429d5ac70f0Sopenharmony_ci int err; 430d5ac70f0Sopenharmony_ci 431d5ac70f0Sopenharmony_ci if (dmix->slowptr) 432d5ac70f0Sopenharmony_ci snd_pcm_hwsync(dmix->spcm); 433d5ac70f0Sopenharmony_ci slave_hw_ptr = *dmix->spcm->hw.ptr; 434d5ac70f0Sopenharmony_ci err = snd_pcm_direct_check_xrun(dmix, pcm); 435d5ac70f0Sopenharmony_ci if (err < 0) 436d5ac70f0Sopenharmony_ci return err; 437d5ac70f0Sopenharmony_ci 438d5ac70f0Sopenharmony_ci return snd_pcm_dmix_sync_ptr0(pcm, slave_hw_ptr); 439d5ac70f0Sopenharmony_ci} 440d5ac70f0Sopenharmony_ci 441d5ac70f0Sopenharmony_ci/* 442d5ac70f0Sopenharmony_ci * plugin implementation 443d5ac70f0Sopenharmony_ci */ 444d5ac70f0Sopenharmony_ci 445d5ac70f0Sopenharmony_cistatic snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm) 446d5ac70f0Sopenharmony_ci{ 447d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 448d5ac70f0Sopenharmony_ci 449d5ac70f0Sopenharmony_ci snd_pcm_direct_check_xrun(dmix, pcm); 450d5ac70f0Sopenharmony_ci if (dmix->state == STATE_RUN_PENDING) 451d5ac70f0Sopenharmony_ci return SNDRV_PCM_STATE_RUNNING; 452d5ac70f0Sopenharmony_ci return dmix->state; 453d5ac70f0Sopenharmony_ci} 454d5ac70f0Sopenharmony_ci 455d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status) 456d5ac70f0Sopenharmony_ci{ 457d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 458d5ac70f0Sopenharmony_ci 459d5ac70f0Sopenharmony_ci memset(status, 0, sizeof(*status)); 460d5ac70f0Sopenharmony_ci snd_pcm_status(dmix->spcm, status); 461d5ac70f0Sopenharmony_ci 462d5ac70f0Sopenharmony_ci switch (dmix->state) { 463d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DRAINING: 464d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 465d5ac70f0Sopenharmony_ci snd_pcm_dmix_sync_ptr0(pcm, status->hw_ptr); 466d5ac70f0Sopenharmony_ci status->delay = snd_pcm_mmap_playback_delay(pcm); 467d5ac70f0Sopenharmony_ci break; 468d5ac70f0Sopenharmony_ci default: 469d5ac70f0Sopenharmony_ci break; 470d5ac70f0Sopenharmony_ci } 471d5ac70f0Sopenharmony_ci 472d5ac70f0Sopenharmony_ci status->state = snd_pcm_dmix_state(pcm); 473d5ac70f0Sopenharmony_ci status->hw_ptr = *pcm->hw.ptr; /* boundary may be different */ 474d5ac70f0Sopenharmony_ci status->appl_ptr = *pcm->appl.ptr; /* slave PCM doesn't set appl_ptr */ 475d5ac70f0Sopenharmony_ci status->trigger_tstamp = dmix->trigger_tstamp; 476d5ac70f0Sopenharmony_ci status->avail = snd_pcm_mmap_playback_avail(pcm); 477d5ac70f0Sopenharmony_ci status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max; 478d5ac70f0Sopenharmony_ci dmix->avail_max = 0; 479d5ac70f0Sopenharmony_ci return 0; 480d5ac70f0Sopenharmony_ci} 481d5ac70f0Sopenharmony_ci 482d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 483d5ac70f0Sopenharmony_ci{ 484d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 485d5ac70f0Sopenharmony_ci int err; 486d5ac70f0Sopenharmony_ci 487d5ac70f0Sopenharmony_ci switch(dmix->state) { 488d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DRAINING: 489d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 490d5ac70f0Sopenharmony_ci err = snd_pcm_dmix_sync_ptr(pcm); 491d5ac70f0Sopenharmony_ci if (err < 0) 492d5ac70f0Sopenharmony_ci return err; 493d5ac70f0Sopenharmony_ci /* fallthru */ 494d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_PREPARED: 495d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_SUSPENDED: 496d5ac70f0Sopenharmony_ci case STATE_RUN_PENDING: 497d5ac70f0Sopenharmony_ci *delayp = snd_pcm_mmap_playback_delay(pcm); 498d5ac70f0Sopenharmony_ci return 0; 499d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_XRUN: 500d5ac70f0Sopenharmony_ci return -EPIPE; 501d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DISCONNECTED: 502d5ac70f0Sopenharmony_ci return -ENODEV; 503d5ac70f0Sopenharmony_ci default: 504d5ac70f0Sopenharmony_ci return -EBADFD; 505d5ac70f0Sopenharmony_ci } 506d5ac70f0Sopenharmony_ci} 507d5ac70f0Sopenharmony_ci 508d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_hwsync(snd_pcm_t *pcm) 509d5ac70f0Sopenharmony_ci{ 510d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 511d5ac70f0Sopenharmony_ci 512d5ac70f0Sopenharmony_ci switch(dmix->state) { 513d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DRAINING: 514d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 515d5ac70f0Sopenharmony_ci /* sync slave PCM */ 516d5ac70f0Sopenharmony_ci return snd_pcm_dmix_sync_ptr(pcm); 517d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_PREPARED: 518d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_SUSPENDED: 519d5ac70f0Sopenharmony_ci case STATE_RUN_PENDING: 520d5ac70f0Sopenharmony_ci return 0; 521d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_XRUN: 522d5ac70f0Sopenharmony_ci return -EPIPE; 523d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DISCONNECTED: 524d5ac70f0Sopenharmony_ci return -ENODEV; 525d5ac70f0Sopenharmony_ci default: 526d5ac70f0Sopenharmony_ci return -EBADFD; 527d5ac70f0Sopenharmony_ci } 528d5ac70f0Sopenharmony_ci} 529d5ac70f0Sopenharmony_ci 530d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_reset(snd_pcm_t *pcm) 531d5ac70f0Sopenharmony_ci{ 532d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 533d5ac70f0Sopenharmony_ci dmix->hw_ptr %= pcm->period_size; 534d5ac70f0Sopenharmony_ci dmix->appl_ptr = dmix->last_appl_ptr = dmix->hw_ptr; 535d5ac70f0Sopenharmony_ci snd_pcm_direct_reset_slave_ptr(pcm, dmix, *dmix->spcm->hw.ptr); 536d5ac70f0Sopenharmony_ci return 0; 537d5ac70f0Sopenharmony_ci} 538d5ac70f0Sopenharmony_ci 539d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dmix) 540d5ac70f0Sopenharmony_ci{ 541d5ac70f0Sopenharmony_ci int err; 542d5ac70f0Sopenharmony_ci 543d5ac70f0Sopenharmony_ci snd_pcm_hwsync(dmix->spcm); 544d5ac70f0Sopenharmony_ci snd_pcm_direct_reset_slave_ptr(pcm, dmix, *dmix->spcm->hw.ptr); 545d5ac70f0Sopenharmony_ci err = snd_timer_start(dmix->timer); 546d5ac70f0Sopenharmony_ci if (err < 0) 547d5ac70f0Sopenharmony_ci return err; 548d5ac70f0Sopenharmony_ci dmix->state = SND_PCM_STATE_RUNNING; 549d5ac70f0Sopenharmony_ci return 0; 550d5ac70f0Sopenharmony_ci} 551d5ac70f0Sopenharmony_ci 552d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_start(snd_pcm_t *pcm) 553d5ac70f0Sopenharmony_ci{ 554d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 555d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail; 556d5ac70f0Sopenharmony_ci int err; 557d5ac70f0Sopenharmony_ci 558d5ac70f0Sopenharmony_ci if (dmix->state != SND_PCM_STATE_PREPARED) 559d5ac70f0Sopenharmony_ci return -EBADFD; 560d5ac70f0Sopenharmony_ci avail = snd_pcm_mmap_playback_hw_avail(pcm); 561d5ac70f0Sopenharmony_ci if (avail == 0) 562d5ac70f0Sopenharmony_ci dmix->state = STATE_RUN_PENDING; 563d5ac70f0Sopenharmony_ci else if (avail < 0) 564d5ac70f0Sopenharmony_ci return 0; 565d5ac70f0Sopenharmony_ci else { 566d5ac70f0Sopenharmony_ci if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0) 567d5ac70f0Sopenharmony_ci return err; 568d5ac70f0Sopenharmony_ci snd_pcm_dmix_sync_area(pcm); 569d5ac70f0Sopenharmony_ci } 570d5ac70f0Sopenharmony_ci gettimestamp(&dmix->trigger_tstamp, pcm->tstamp_type); 571d5ac70f0Sopenharmony_ci return 0; 572d5ac70f0Sopenharmony_ci} 573d5ac70f0Sopenharmony_ci 574d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_drop(snd_pcm_t *pcm) 575d5ac70f0Sopenharmony_ci{ 576d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 577d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_OPEN) 578d5ac70f0Sopenharmony_ci return -EBADFD; 579d5ac70f0Sopenharmony_ci dmix->state = SND_PCM_STATE_SETUP; 580d5ac70f0Sopenharmony_ci snd_pcm_direct_timer_stop(dmix); 581d5ac70f0Sopenharmony_ci return 0; 582d5ac70f0Sopenharmony_ci} 583d5ac70f0Sopenharmony_ci 584d5ac70f0Sopenharmony_ci/* locked version */ 585d5ac70f0Sopenharmony_cistatic int __snd_pcm_dmix_drain(snd_pcm_t *pcm) 586d5ac70f0Sopenharmony_ci{ 587d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 588d5ac70f0Sopenharmony_ci snd_pcm_uframes_t stop_threshold; 589d5ac70f0Sopenharmony_ci int err = 0; 590d5ac70f0Sopenharmony_ci 591d5ac70f0Sopenharmony_ci switch (snd_pcm_state(dmix->spcm)) { 592d5ac70f0Sopenharmony_ci case SND_PCM_STATE_SUSPENDED: 593d5ac70f0Sopenharmony_ci return -ESTRPIPE; 594d5ac70f0Sopenharmony_ci default: 595d5ac70f0Sopenharmony_ci break; 596d5ac70f0Sopenharmony_ci } 597d5ac70f0Sopenharmony_ci 598d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_OPEN) 599d5ac70f0Sopenharmony_ci return -EBADFD; 600d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_PREPARED) { 601d5ac70f0Sopenharmony_ci if (snd_pcm_mmap_playback_hw_avail(pcm) > 0) 602d5ac70f0Sopenharmony_ci snd_pcm_dmix_start(pcm); 603d5ac70f0Sopenharmony_ci else { 604d5ac70f0Sopenharmony_ci snd_pcm_dmix_drop(pcm); 605d5ac70f0Sopenharmony_ci return 0; 606d5ac70f0Sopenharmony_ci } 607d5ac70f0Sopenharmony_ci } 608d5ac70f0Sopenharmony_ci 609d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_XRUN) { 610d5ac70f0Sopenharmony_ci snd_pcm_dmix_drop(pcm); 611d5ac70f0Sopenharmony_ci return 0; 612d5ac70f0Sopenharmony_ci } 613d5ac70f0Sopenharmony_ci 614d5ac70f0Sopenharmony_ci stop_threshold = pcm->stop_threshold; 615d5ac70f0Sopenharmony_ci if (pcm->stop_threshold > pcm->buffer_size) 616d5ac70f0Sopenharmony_ci pcm->stop_threshold = pcm->buffer_size; 617d5ac70f0Sopenharmony_ci dmix->state = SND_PCM_STATE_DRAINING; 618d5ac70f0Sopenharmony_ci do { 619d5ac70f0Sopenharmony_ci err = snd_pcm_dmix_sync_ptr(pcm); 620d5ac70f0Sopenharmony_ci if (err < 0) { 621d5ac70f0Sopenharmony_ci snd_pcm_dmix_drop(pcm); 622d5ac70f0Sopenharmony_ci goto done; 623d5ac70f0Sopenharmony_ci } 624d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_DRAINING) { 625d5ac70f0Sopenharmony_ci snd_pcm_dmix_sync_area(pcm); 626d5ac70f0Sopenharmony_ci if ((pcm->mode & SND_PCM_NONBLOCK) == 0) { 627d5ac70f0Sopenharmony_ci snd_pcm_wait_nocheck(pcm, SND_PCM_WAIT_DRAIN); 628d5ac70f0Sopenharmony_ci snd_pcm_direct_clear_timer_queue(dmix); /* force poll to wait */ 629d5ac70f0Sopenharmony_ci } 630d5ac70f0Sopenharmony_ci 631d5ac70f0Sopenharmony_ci switch (snd_pcm_state(dmix->spcm)) { 632d5ac70f0Sopenharmony_ci case SND_PCM_STATE_SUSPENDED: 633d5ac70f0Sopenharmony_ci err = -ESTRPIPE; 634d5ac70f0Sopenharmony_ci goto done; 635d5ac70f0Sopenharmony_ci default: 636d5ac70f0Sopenharmony_ci break; 637d5ac70f0Sopenharmony_ci } 638d5ac70f0Sopenharmony_ci } 639d5ac70f0Sopenharmony_ci if (pcm->mode & SND_PCM_NONBLOCK) { 640d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_DRAINING) { 641d5ac70f0Sopenharmony_ci err = -EAGAIN; 642d5ac70f0Sopenharmony_ci goto done; 643d5ac70f0Sopenharmony_ci } 644d5ac70f0Sopenharmony_ci } 645d5ac70f0Sopenharmony_ci } while (dmix->state == SND_PCM_STATE_DRAINING); 646d5ac70f0Sopenharmony_cidone: 647d5ac70f0Sopenharmony_ci pcm->stop_threshold = stop_threshold; 648d5ac70f0Sopenharmony_ci return err; 649d5ac70f0Sopenharmony_ci} 650d5ac70f0Sopenharmony_ci 651d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_drain(snd_pcm_t *pcm) 652d5ac70f0Sopenharmony_ci{ 653d5ac70f0Sopenharmony_ci int err; 654d5ac70f0Sopenharmony_ci 655d5ac70f0Sopenharmony_ci snd_pcm_lock(pcm); 656d5ac70f0Sopenharmony_ci err = __snd_pcm_dmix_drain(pcm); 657d5ac70f0Sopenharmony_ci snd_pcm_unlock(pcm); 658d5ac70f0Sopenharmony_ci return err; 659d5ac70f0Sopenharmony_ci} 660d5ac70f0Sopenharmony_ci 661d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED) 662d5ac70f0Sopenharmony_ci{ 663d5ac70f0Sopenharmony_ci return -EIO; 664d5ac70f0Sopenharmony_ci} 665d5ac70f0Sopenharmony_ci 666d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dmix_rewindable(snd_pcm_t *pcm) 667d5ac70f0Sopenharmony_ci{ 668d5ac70f0Sopenharmony_ci return snd_pcm_mmap_playback_hw_rewindable(pcm); 669d5ac70f0Sopenharmony_ci} 670d5ac70f0Sopenharmony_ci 671d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 672d5ac70f0Sopenharmony_ci{ 673d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 674d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_appl_ptr, slave_size; 675d5ac70f0Sopenharmony_ci snd_pcm_uframes_t appl_ptr, size, transfer, result, frames_to_remix; 676d5ac70f0Sopenharmony_ci int err; 677d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, *dst_areas; 678d5ac70f0Sopenharmony_ci 679d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_RUNNING || 680d5ac70f0Sopenharmony_ci dmix->state == SND_PCM_STATE_DRAINING) { 681d5ac70f0Sopenharmony_ci err = snd_pcm_dmix_hwsync(pcm); 682d5ac70f0Sopenharmony_ci if (err < 0) 683d5ac70f0Sopenharmony_ci return err; 684d5ac70f0Sopenharmony_ci } 685d5ac70f0Sopenharmony_ci 686d5ac70f0Sopenharmony_ci /* (appl_ptr - last_appl_ptr) indicates the frames which are not 687d5ac70f0Sopenharmony_ci * already mixed 688d5ac70f0Sopenharmony_ci * (last_appl_ptr - hw_ptr) indicates the frames which are already 689d5ac70f0Sopenharmony_ci * mixed but not played yet. 690d5ac70f0Sopenharmony_ci * So they can be remixed. 691d5ac70f0Sopenharmony_ci */ 692d5ac70f0Sopenharmony_ci 693d5ac70f0Sopenharmony_ci size = pcm_frame_diff(dmix->last_appl_ptr, dmix->appl_ptr, pcm->boundary); 694d5ac70f0Sopenharmony_ci if (frames < size) 695d5ac70f0Sopenharmony_ci size = frames; 696d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_backward(pcm, size); 697d5ac70f0Sopenharmony_ci frames -= size; 698d5ac70f0Sopenharmony_ci if (!frames) 699d5ac70f0Sopenharmony_ci return size; 700d5ac70f0Sopenharmony_ci result = size; 701d5ac70f0Sopenharmony_ci 702d5ac70f0Sopenharmony_ci /* Always at this point last_appl_ptr == appl_ptr 703d5ac70f0Sopenharmony_ci * So (appl_ptr - hw_ptr) indicates the frames which can be remixed 704d5ac70f0Sopenharmony_ci */ 705d5ac70f0Sopenharmony_ci size = pcm_frame_diff(dmix->appl_ptr, dmix->hw_ptr, pcm->boundary); 706d5ac70f0Sopenharmony_ci if (size > frames) 707d5ac70f0Sopenharmony_ci size = frames; 708d5ac70f0Sopenharmony_ci slave_size = pcm_frame_diff(dmix->slave_appl_ptr, dmix->slave_hw_ptr, pcm->boundary); 709d5ac70f0Sopenharmony_ci if (slave_size < size) 710d5ac70f0Sopenharmony_ci size = slave_size; 711d5ac70f0Sopenharmony_ci 712d5ac70f0Sopenharmony_ci /* frames which should be remixed will be saved 713d5ac70f0Sopenharmony_ci * to also backward the appl pointer on success 714d5ac70f0Sopenharmony_ci */ 715d5ac70f0Sopenharmony_ci frames_to_remix = size; 716d5ac70f0Sopenharmony_ci 717d5ac70f0Sopenharmony_ci /* add sample areas here */ 718d5ac70f0Sopenharmony_ci src_areas = snd_pcm_mmap_areas(pcm); 719d5ac70f0Sopenharmony_ci dst_areas = snd_pcm_mmap_areas(dmix->spcm); 720d5ac70f0Sopenharmony_ci dmix->last_appl_ptr -= size; 721d5ac70f0Sopenharmony_ci dmix->last_appl_ptr %= pcm->boundary; 722d5ac70f0Sopenharmony_ci appl_ptr = dmix->last_appl_ptr % pcm->buffer_size; 723d5ac70f0Sopenharmony_ci dmix->slave_appl_ptr -= size; 724d5ac70f0Sopenharmony_ci dmix->slave_appl_ptr %= dmix->slave_boundary; 725d5ac70f0Sopenharmony_ci slave_appl_ptr = dmix->slave_appl_ptr % dmix->slave_buffer_size; 726d5ac70f0Sopenharmony_ci dmix_down_sem(dmix); 727d5ac70f0Sopenharmony_ci for (;;) { 728d5ac70f0Sopenharmony_ci transfer = size; 729d5ac70f0Sopenharmony_ci if (appl_ptr + transfer > pcm->buffer_size) 730d5ac70f0Sopenharmony_ci transfer = pcm->buffer_size - appl_ptr; 731d5ac70f0Sopenharmony_ci if (slave_appl_ptr + transfer > dmix->slave_buffer_size) 732d5ac70f0Sopenharmony_ci transfer = dmix->slave_buffer_size - slave_appl_ptr; 733d5ac70f0Sopenharmony_ci remix_areas(dmix, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); 734d5ac70f0Sopenharmony_ci size -= transfer; 735d5ac70f0Sopenharmony_ci if (! size) 736d5ac70f0Sopenharmony_ci break; 737d5ac70f0Sopenharmony_ci slave_appl_ptr += transfer; 738d5ac70f0Sopenharmony_ci slave_appl_ptr %= dmix->slave_buffer_size; 739d5ac70f0Sopenharmony_ci appl_ptr += transfer; 740d5ac70f0Sopenharmony_ci appl_ptr %= pcm->buffer_size; 741d5ac70f0Sopenharmony_ci } 742d5ac70f0Sopenharmony_ci dmix_up_sem(dmix); 743d5ac70f0Sopenharmony_ci 744d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_backward(pcm, frames_to_remix); 745d5ac70f0Sopenharmony_ci result += frames_to_remix; 746d5ac70f0Sopenharmony_ci /* At this point last_appl_ptr and appl_ptr has to indicate the 747d5ac70f0Sopenharmony_ci * position of the first not mixed frame 748d5ac70f0Sopenharmony_ci */ 749d5ac70f0Sopenharmony_ci 750d5ac70f0Sopenharmony_ci return result; 751d5ac70f0Sopenharmony_ci} 752d5ac70f0Sopenharmony_ci 753d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dmix_forwardable(snd_pcm_t *pcm) 754d5ac70f0Sopenharmony_ci{ 755d5ac70f0Sopenharmony_ci return snd_pcm_mmap_avail(pcm); 756d5ac70f0Sopenharmony_ci} 757d5ac70f0Sopenharmony_ci 758d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 759d5ac70f0Sopenharmony_ci{ 760d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail; 761d5ac70f0Sopenharmony_ci 762d5ac70f0Sopenharmony_ci avail = snd_pcm_dmix_forwardable(pcm); 763d5ac70f0Sopenharmony_ci if (frames > (snd_pcm_uframes_t)avail) 764d5ac70f0Sopenharmony_ci frames = avail; 765d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, frames); 766d5ac70f0Sopenharmony_ci return frames; 767d5ac70f0Sopenharmony_ci} 768d5ac70f0Sopenharmony_ci 769d5ac70f0Sopenharmony_cistatic 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) 770d5ac70f0Sopenharmony_ci{ 771d5ac70f0Sopenharmony_ci return -ENODEV; 772d5ac70f0Sopenharmony_ci} 773d5ac70f0Sopenharmony_ci 774d5ac70f0Sopenharmony_cistatic 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) 775d5ac70f0Sopenharmony_ci{ 776d5ac70f0Sopenharmony_ci return -ENODEV; 777d5ac70f0Sopenharmony_ci} 778d5ac70f0Sopenharmony_ci 779d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_close(snd_pcm_t *pcm) 780d5ac70f0Sopenharmony_ci{ 781d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 782d5ac70f0Sopenharmony_ci 783d5ac70f0Sopenharmony_ci if (dmix->timer) 784d5ac70f0Sopenharmony_ci snd_timer_close(dmix->timer); 785d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); 786d5ac70f0Sopenharmony_ci snd_pcm_close(dmix->spcm); 787d5ac70f0Sopenharmony_ci if (dmix->server) 788d5ac70f0Sopenharmony_ci snd_pcm_direct_server_discard(dmix); 789d5ac70f0Sopenharmony_ci if (dmix->client) 790d5ac70f0Sopenharmony_ci snd_pcm_direct_client_discard(dmix); 791d5ac70f0Sopenharmony_ci shm_sum_discard(dmix); 792d5ac70f0Sopenharmony_ci if (snd_pcm_direct_shm_discard(dmix)) { 793d5ac70f0Sopenharmony_ci if (snd_pcm_direct_semaphore_discard(dmix)) 794d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT); 795d5ac70f0Sopenharmony_ci } else 796d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT); 797d5ac70f0Sopenharmony_ci free(dmix->bindings); 798d5ac70f0Sopenharmony_ci pcm->private_data = NULL; 799d5ac70f0Sopenharmony_ci free(dmix); 800d5ac70f0Sopenharmony_ci return 0; 801d5ac70f0Sopenharmony_ci} 802d5ac70f0Sopenharmony_ci 803d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, 804d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, 805d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 806d5ac70f0Sopenharmony_ci{ 807d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 808d5ac70f0Sopenharmony_ci int err; 809d5ac70f0Sopenharmony_ci 810d5ac70f0Sopenharmony_ci err = snd_pcm_direct_check_xrun(dmix, pcm); 811d5ac70f0Sopenharmony_ci if (err < 0) 812d5ac70f0Sopenharmony_ci return err; 813d5ac70f0Sopenharmony_ci if (! size) 814d5ac70f0Sopenharmony_ci return 0; 815d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, size); 816d5ac70f0Sopenharmony_ci if (dmix->state == STATE_RUN_PENDING) { 817d5ac70f0Sopenharmony_ci if ((err = snd_pcm_dmix_start_timer(pcm, dmix)) < 0) 818d5ac70f0Sopenharmony_ci return err; 819d5ac70f0Sopenharmony_ci } else if (dmix->state == SND_PCM_STATE_RUNNING || 820d5ac70f0Sopenharmony_ci dmix->state == SND_PCM_STATE_DRAINING) { 821d5ac70f0Sopenharmony_ci if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0) 822d5ac70f0Sopenharmony_ci return err; 823d5ac70f0Sopenharmony_ci } 824d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_RUNNING || 825d5ac70f0Sopenharmony_ci dmix->state == SND_PCM_STATE_DRAINING) { 826d5ac70f0Sopenharmony_ci /* ok, we commit the changes after the validation of area */ 827d5ac70f0Sopenharmony_ci /* it's intended, although the result might be crappy */ 828d5ac70f0Sopenharmony_ci snd_pcm_dmix_sync_area(pcm); 829d5ac70f0Sopenharmony_ci /* clear timer queue to avoid a bogus return from poll */ 830d5ac70f0Sopenharmony_ci if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min) 831d5ac70f0Sopenharmony_ci snd_pcm_direct_clear_timer_queue(dmix); 832d5ac70f0Sopenharmony_ci } 833d5ac70f0Sopenharmony_ci return size; 834d5ac70f0Sopenharmony_ci} 835d5ac70f0Sopenharmony_ci 836d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm) 837d5ac70f0Sopenharmony_ci{ 838d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 839d5ac70f0Sopenharmony_ci int err; 840d5ac70f0Sopenharmony_ci 841d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_RUNNING || 842d5ac70f0Sopenharmony_ci dmix->state == SND_PCM_STATE_DRAINING) { 843d5ac70f0Sopenharmony_ci if ((err = snd_pcm_dmix_sync_ptr(pcm)) < 0) 844d5ac70f0Sopenharmony_ci return err; 845d5ac70f0Sopenharmony_ci } 846d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_XRUN) 847d5ac70f0Sopenharmony_ci return -EPIPE; 848d5ac70f0Sopenharmony_ci 849d5ac70f0Sopenharmony_ci return snd_pcm_mmap_playback_avail(pcm); 850d5ac70f0Sopenharmony_ci} 851d5ac70f0Sopenharmony_ci 852d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_htimestamp(snd_pcm_t *pcm, 853d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *avail, 854d5ac70f0Sopenharmony_ci snd_htimestamp_t *tstamp) 855d5ac70f0Sopenharmony_ci{ 856d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 857d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail1; 858d5ac70f0Sopenharmony_ci int ok = 0; 859d5ac70f0Sopenharmony_ci 860d5ac70f0Sopenharmony_ci while (1) { 861d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_RUNNING || 862d5ac70f0Sopenharmony_ci dmix->state == SND_PCM_STATE_DRAINING) 863d5ac70f0Sopenharmony_ci snd_pcm_dmix_sync_ptr(pcm); 864d5ac70f0Sopenharmony_ci avail1 = snd_pcm_mmap_playback_avail(pcm); 865d5ac70f0Sopenharmony_ci if (ok && *avail == avail1) 866d5ac70f0Sopenharmony_ci break; 867d5ac70f0Sopenharmony_ci *avail = avail1; 868d5ac70f0Sopenharmony_ci *tstamp = snd_pcm_hw_fast_tstamp(dmix->spcm); 869d5ac70f0Sopenharmony_ci ok = 1; 870d5ac70f0Sopenharmony_ci } 871d5ac70f0Sopenharmony_ci return 0; 872d5ac70f0Sopenharmony_ci} 873d5ac70f0Sopenharmony_ci 874d5ac70f0Sopenharmony_cistatic int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) 875d5ac70f0Sopenharmony_ci{ 876d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 877d5ac70f0Sopenharmony_ci if (dmix->state == SND_PCM_STATE_RUNNING) 878d5ac70f0Sopenharmony_ci snd_pcm_dmix_sync_area(pcm); 879d5ac70f0Sopenharmony_ci return snd_pcm_direct_poll_revents(pcm, pfds, nfds, revents); 880d5ac70f0Sopenharmony_ci} 881d5ac70f0Sopenharmony_ci 882d5ac70f0Sopenharmony_ci 883d5ac70f0Sopenharmony_cistatic void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out) 884d5ac70f0Sopenharmony_ci{ 885d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix = pcm->private_data; 886d5ac70f0Sopenharmony_ci 887d5ac70f0Sopenharmony_ci snd_output_printf(out, "Direct Stream Mixing PCM\n"); 888d5ac70f0Sopenharmony_ci if (pcm->setup) { 889d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 890d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 891d5ac70f0Sopenharmony_ci } 892d5ac70f0Sopenharmony_ci if (dmix->spcm) 893d5ac70f0Sopenharmony_ci snd_pcm_dump(dmix->spcm, out); 894d5ac70f0Sopenharmony_ci} 895d5ac70f0Sopenharmony_ci 896d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_dmix_ops = { 897d5ac70f0Sopenharmony_ci .close = snd_pcm_dmix_close, 898d5ac70f0Sopenharmony_ci .info = snd_pcm_direct_info, 899d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_direct_hw_refine, 900d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_direct_hw_params, 901d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_direct_hw_free, 902d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_direct_sw_params, 903d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_direct_channel_info, 904d5ac70f0Sopenharmony_ci .dump = snd_pcm_dmix_dump, 905d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_direct_nonblock, 906d5ac70f0Sopenharmony_ci .async = snd_pcm_direct_async, 907d5ac70f0Sopenharmony_ci .mmap = snd_pcm_direct_mmap, 908d5ac70f0Sopenharmony_ci .munmap = snd_pcm_direct_munmap, 909d5ac70f0Sopenharmony_ci .query_chmaps = snd_pcm_direct_query_chmaps, 910d5ac70f0Sopenharmony_ci .get_chmap = snd_pcm_direct_get_chmap, 911d5ac70f0Sopenharmony_ci .set_chmap = snd_pcm_direct_set_chmap, 912d5ac70f0Sopenharmony_ci}; 913d5ac70f0Sopenharmony_ci 914d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = { 915d5ac70f0Sopenharmony_ci .status = snd_pcm_dmix_status, 916d5ac70f0Sopenharmony_ci .state = snd_pcm_dmix_state, 917d5ac70f0Sopenharmony_ci .hwsync = snd_pcm_dmix_hwsync, 918d5ac70f0Sopenharmony_ci .delay = snd_pcm_dmix_delay, 919d5ac70f0Sopenharmony_ci .prepare = snd_pcm_direct_prepare, 920d5ac70f0Sopenharmony_ci .reset = snd_pcm_dmix_reset, 921d5ac70f0Sopenharmony_ci .start = snd_pcm_dmix_start, 922d5ac70f0Sopenharmony_ci .drop = snd_pcm_dmix_drop, 923d5ac70f0Sopenharmony_ci .drain = snd_pcm_dmix_drain, 924d5ac70f0Sopenharmony_ci .pause = snd_pcm_dmix_pause, 925d5ac70f0Sopenharmony_ci .rewindable = snd_pcm_dmix_rewindable, 926d5ac70f0Sopenharmony_ci .rewind = snd_pcm_dmix_rewind, 927d5ac70f0Sopenharmony_ci .forwardable = snd_pcm_dmix_forwardable, 928d5ac70f0Sopenharmony_ci .forward = snd_pcm_dmix_forward, 929d5ac70f0Sopenharmony_ci .resume = snd_pcm_direct_resume, 930d5ac70f0Sopenharmony_ci .link = NULL, 931d5ac70f0Sopenharmony_ci .link_slaves = NULL, 932d5ac70f0Sopenharmony_ci .unlink = NULL, 933d5ac70f0Sopenharmony_ci .writei = snd_pcm_mmap_writei, 934d5ac70f0Sopenharmony_ci .writen = snd_pcm_mmap_writen, 935d5ac70f0Sopenharmony_ci .readi = snd_pcm_dmix_readi, 936d5ac70f0Sopenharmony_ci .readn = snd_pcm_dmix_readn, 937d5ac70f0Sopenharmony_ci .avail_update = snd_pcm_dmix_avail_update, 938d5ac70f0Sopenharmony_ci .mmap_commit = snd_pcm_dmix_mmap_commit, 939d5ac70f0Sopenharmony_ci .htimestamp = snd_pcm_dmix_htimestamp, 940d5ac70f0Sopenharmony_ci .poll_descriptors = snd_pcm_direct_poll_descriptors, 941d5ac70f0Sopenharmony_ci .poll_descriptors_count = NULL, 942d5ac70f0Sopenharmony_ci .poll_revents = snd_pcm_dmix_poll_revents, 943d5ac70f0Sopenharmony_ci}; 944d5ac70f0Sopenharmony_ci 945d5ac70f0Sopenharmony_ci/** 946d5ac70f0Sopenharmony_ci * \brief Creates a new dmix PCM 947d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 948d5ac70f0Sopenharmony_ci * \param name Name of PCM 949d5ac70f0Sopenharmony_ci * \param opts Direct PCM configurations 950d5ac70f0Sopenharmony_ci * \param params Parameters for slave 951d5ac70f0Sopenharmony_ci * \param root Configuration root 952d5ac70f0Sopenharmony_ci * \param sconf Slave configuration 953d5ac70f0Sopenharmony_ci * \param stream PCM Direction (stream) 954d5ac70f0Sopenharmony_ci * \param mode PCM Mode 955d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 956d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 957d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 958d5ac70f0Sopenharmony_ci * changed in future. 959d5ac70f0Sopenharmony_ci */ 960d5ac70f0Sopenharmony_ciint snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, 961d5ac70f0Sopenharmony_ci struct snd_pcm_direct_open_conf *opts, 962d5ac70f0Sopenharmony_ci struct slave_params *params, 963d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *sconf, 964d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 965d5ac70f0Sopenharmony_ci{ 966d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, *spcm = NULL; 967d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dmix; 968d5ac70f0Sopenharmony_ci int ret, first_instance; 969d5ac70f0Sopenharmony_ci 970d5ac70f0Sopenharmony_ci assert(pcmp); 971d5ac70f0Sopenharmony_ci 972d5ac70f0Sopenharmony_ci if (stream != SND_PCM_STREAM_PLAYBACK) { 973d5ac70f0Sopenharmony_ci SNDERR("The dmix plugin supports only playback stream"); 974d5ac70f0Sopenharmony_ci return -EINVAL; 975d5ac70f0Sopenharmony_ci } 976d5ac70f0Sopenharmony_ci 977d5ac70f0Sopenharmony_ci ret = _snd_pcm_direct_new(&pcm, &dmix, SND_PCM_TYPE_DMIX, name, opts, params, stream, mode); 978d5ac70f0Sopenharmony_ci if (ret < 0) 979d5ac70f0Sopenharmony_ci return ret; 980d5ac70f0Sopenharmony_ci first_instance = ret; 981d5ac70f0Sopenharmony_ci 982d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_dmix_ops; 983d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_dmix_fast_ops; 984d5ac70f0Sopenharmony_ci pcm->private_data = dmix; 985d5ac70f0Sopenharmony_ci dmix->state = SND_PCM_STATE_OPEN; 986d5ac70f0Sopenharmony_ci dmix->slowptr = opts->slowptr; 987d5ac70f0Sopenharmony_ci dmix->max_periods = opts->max_periods; 988d5ac70f0Sopenharmony_ci dmix->var_periodsize = opts->var_periodsize; 989d5ac70f0Sopenharmony_ci dmix->hw_ptr_alignment = opts->hw_ptr_alignment; 990d5ac70f0Sopenharmony_ci dmix->sync_ptr = snd_pcm_dmix_sync_ptr; 991d5ac70f0Sopenharmony_ci dmix->direct_memory_access = opts->direct_memory_access; 992d5ac70f0Sopenharmony_ci 993d5ac70f0Sopenharmony_ci retry: 994d5ac70f0Sopenharmony_ci if (first_instance) { 995d5ac70f0Sopenharmony_ci /* recursion is already checked in 996d5ac70f0Sopenharmony_ci snd_pcm_direct_get_slave_ipc_offset() */ 997d5ac70f0Sopenharmony_ci ret = snd_pcm_open_slave(&spcm, root, sconf, stream, 998d5ac70f0Sopenharmony_ci mode | SND_PCM_NONBLOCK, NULL); 999d5ac70f0Sopenharmony_ci if (ret < 0) { 1000d5ac70f0Sopenharmony_ci SNDERR("unable to open slave"); 1001d5ac70f0Sopenharmony_ci goto _err; 1002d5ac70f0Sopenharmony_ci } 1003d5ac70f0Sopenharmony_ci 1004d5ac70f0Sopenharmony_ci if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { 1005d5ac70f0Sopenharmony_ci SNDERR("dmix plugin can be only connected to hw plugin"); 1006d5ac70f0Sopenharmony_ci ret = -EINVAL; 1007d5ac70f0Sopenharmony_ci goto _err; 1008d5ac70f0Sopenharmony_ci } 1009d5ac70f0Sopenharmony_ci 1010d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_initialize_slave(dmix, spcm, params); 1011d5ac70f0Sopenharmony_ci if (ret < 0) { 1012d5ac70f0Sopenharmony_ci SNDERR("unable to initialize slave"); 1013d5ac70f0Sopenharmony_ci goto _err; 1014d5ac70f0Sopenharmony_ci } 1015d5ac70f0Sopenharmony_ci 1016d5ac70f0Sopenharmony_ci dmix->spcm = spcm; 1017d5ac70f0Sopenharmony_ci 1018d5ac70f0Sopenharmony_ci if (dmix->shmptr->use_server) { 1019d5ac70f0Sopenharmony_ci dmix->server_free = dmix_server_free; 1020d5ac70f0Sopenharmony_ci 1021d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_server_create(dmix); 1022d5ac70f0Sopenharmony_ci if (ret < 0) { 1023d5ac70f0Sopenharmony_ci SNDERR("unable to create server"); 1024d5ac70f0Sopenharmony_ci goto _err; 1025d5ac70f0Sopenharmony_ci } 1026d5ac70f0Sopenharmony_ci } 1027d5ac70f0Sopenharmony_ci 1028d5ac70f0Sopenharmony_ci dmix->shmptr->type = spcm->type; 1029d5ac70f0Sopenharmony_ci } else { 1030d5ac70f0Sopenharmony_ci if (dmix->shmptr->use_server) { 1031d5ac70f0Sopenharmony_ci /* up semaphore to avoid deadlock */ 1032d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); 1033d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_client_connect(dmix); 1034d5ac70f0Sopenharmony_ci if (ret < 0) { 1035d5ac70f0Sopenharmony_ci SNDERR("unable to connect client"); 1036d5ac70f0Sopenharmony_ci goto _err_nosem; 1037d5ac70f0Sopenharmony_ci } 1038d5ac70f0Sopenharmony_ci 1039d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); 1040d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client"); 1041d5ac70f0Sopenharmony_ci if (ret < 0) 1042d5ac70f0Sopenharmony_ci goto _err; 1043d5ac70f0Sopenharmony_ci } else { 1044d5ac70f0Sopenharmony_ci 1045d5ac70f0Sopenharmony_ci ret = snd_pcm_open_slave(&spcm, root, sconf, stream, 1046d5ac70f0Sopenharmony_ci mode | SND_PCM_NONBLOCK | 1047d5ac70f0Sopenharmony_ci SND_PCM_APPEND, 1048d5ac70f0Sopenharmony_ci NULL); 1049d5ac70f0Sopenharmony_ci if (ret < 0) { 1050d5ac70f0Sopenharmony_ci /* all other streams have been closed; 1051d5ac70f0Sopenharmony_ci * retry as the first instance 1052d5ac70f0Sopenharmony_ci */ 1053d5ac70f0Sopenharmony_ci if (ret == -EBADFD) { 1054d5ac70f0Sopenharmony_ci first_instance = 1; 1055d5ac70f0Sopenharmony_ci goto retry; 1056d5ac70f0Sopenharmony_ci } 1057d5ac70f0Sopenharmony_ci SNDERR("unable to open slave"); 1058d5ac70f0Sopenharmony_ci goto _err; 1059d5ac70f0Sopenharmony_ci } 1060d5ac70f0Sopenharmony_ci if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { 1061d5ac70f0Sopenharmony_ci SNDERR("dmix plugin can be only connected to hw plugin"); 1062d5ac70f0Sopenharmony_ci ret = -EINVAL; 1063d5ac70f0Sopenharmony_ci goto _err; 1064d5ac70f0Sopenharmony_ci } 1065d5ac70f0Sopenharmony_ci 1066d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params); 1067d5ac70f0Sopenharmony_ci if (ret < 0) { 1068d5ac70f0Sopenharmony_ci SNDERR("unable to initialize slave"); 1069d5ac70f0Sopenharmony_ci goto _err; 1070d5ac70f0Sopenharmony_ci } 1071d5ac70f0Sopenharmony_ci } 1072d5ac70f0Sopenharmony_ci 1073d5ac70f0Sopenharmony_ci dmix->spcm = spcm; 1074d5ac70f0Sopenharmony_ci } 1075d5ac70f0Sopenharmony_ci 1076d5ac70f0Sopenharmony_ci ret = shm_sum_create_or_connect(dmix); 1077d5ac70f0Sopenharmony_ci if (ret < 0) { 1078d5ac70f0Sopenharmony_ci SNDERR("unable to initialize sum ring buffer"); 1079d5ac70f0Sopenharmony_ci goto _err; 1080d5ac70f0Sopenharmony_ci } 1081d5ac70f0Sopenharmony_ci 1082d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_initialize_poll_fd(dmix); 1083d5ac70f0Sopenharmony_ci if (ret < 0) { 1084d5ac70f0Sopenharmony_ci SNDERR("unable to initialize poll_fd"); 1085d5ac70f0Sopenharmony_ci goto _err; 1086d5ac70f0Sopenharmony_ci } 1087d5ac70f0Sopenharmony_ci 1088d5ac70f0Sopenharmony_ci mix_select_callbacks(dmix); 1089d5ac70f0Sopenharmony_ci 1090d5ac70f0Sopenharmony_ci pcm->poll_fd = dmix->poll_fd; 1091d5ac70f0Sopenharmony_ci pcm->poll_events = POLLIN; /* it's different than other plugins */ 1092d5ac70f0Sopenharmony_ci pcm->tstamp_type = spcm->tstamp_type; 1093d5ac70f0Sopenharmony_ci pcm->mmap_rw = 1; 1094d5ac70f0Sopenharmony_ci snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0); 1095d5ac70f0Sopenharmony_ci snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0); 1096d5ac70f0Sopenharmony_ci 1097d5ac70f0Sopenharmony_ci if (dmix->channels == UINT_MAX) 1098d5ac70f0Sopenharmony_ci dmix->channels = dmix->shmptr->s.channels; 1099d5ac70f0Sopenharmony_ci 1100d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); 1101d5ac70f0Sopenharmony_ci 1102d5ac70f0Sopenharmony_ci *pcmp = pcm; 1103d5ac70f0Sopenharmony_ci return 0; 1104d5ac70f0Sopenharmony_ci 1105d5ac70f0Sopenharmony_ci _err: 1106d5ac70f0Sopenharmony_ci if (dmix->timer) 1107d5ac70f0Sopenharmony_ci snd_timer_close(dmix->timer); 1108d5ac70f0Sopenharmony_ci if (dmix->server) 1109d5ac70f0Sopenharmony_ci snd_pcm_direct_server_discard(dmix); 1110d5ac70f0Sopenharmony_ci if (dmix->client) 1111d5ac70f0Sopenharmony_ci snd_pcm_direct_client_discard(dmix); 1112d5ac70f0Sopenharmony_ci if (spcm) 1113d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 1114d5ac70f0Sopenharmony_ci if (dmix->u.dmix.shmid_sum >= 0) 1115d5ac70f0Sopenharmony_ci shm_sum_discard(dmix); 1116d5ac70f0Sopenharmony_ci if ((dmix->shmid >= 0) && (snd_pcm_direct_shm_discard(dmix))) { 1117d5ac70f0Sopenharmony_ci if (snd_pcm_direct_semaphore_discard(dmix)) 1118d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_final(dmix, DIRECT_IPC_SEM_CLIENT); 1119d5ac70f0Sopenharmony_ci } else 1120d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); 1121d5ac70f0Sopenharmony_ci _err_nosem: 1122d5ac70f0Sopenharmony_ci free(dmix->bindings); 1123d5ac70f0Sopenharmony_ci free(dmix); 1124d5ac70f0Sopenharmony_ci snd_pcm_free(pcm); 1125d5ac70f0Sopenharmony_ci return ret; 1126d5ac70f0Sopenharmony_ci} 1127d5ac70f0Sopenharmony_ci 1128d5ac70f0Sopenharmony_ci/*! \page pcm_plugins 1129d5ac70f0Sopenharmony_ci 1130d5ac70f0Sopenharmony_ci\section pcm_plugins_dmix Plugin: dmix 1131d5ac70f0Sopenharmony_ci 1132d5ac70f0Sopenharmony_ciThis plugin provides direct mixing of multiple streams. The resolution 1133d5ac70f0Sopenharmony_cifor 32-bit mixing is only 24-bit. The low significant byte is filled with 1134d5ac70f0Sopenharmony_cizeros. The extra 8 bits are used for the saturation. 1135d5ac70f0Sopenharmony_ci 1136d5ac70f0Sopenharmony_ci\code 1137d5ac70f0Sopenharmony_cipcm.name { 1138d5ac70f0Sopenharmony_ci type dmix # Direct mix 1139d5ac70f0Sopenharmony_ci ipc_key INT # unique IPC key 1140d5ac70f0Sopenharmony_ci ipc_key_add_uid BOOL # add current uid to unique IPC key 1141d5ac70f0Sopenharmony_ci ipc_perm INT # IPC permissions (octal, default 0600) 1142d5ac70f0Sopenharmony_ci hw_ptr_alignment STR # Slave application and hw pointer alignment type 1143d5ac70f0Sopenharmony_ci # STR can be one of the below strings : 1144d5ac70f0Sopenharmony_ci # no (or off) 1145d5ac70f0Sopenharmony_ci # roundup 1146d5ac70f0Sopenharmony_ci # rounddown 1147d5ac70f0Sopenharmony_ci # auto (default) 1148d5ac70f0Sopenharmony_ci tstamp_type STR # timestamp type 1149d5ac70f0Sopenharmony_ci # STR can be one of the below strings : 1150d5ac70f0Sopenharmony_ci # default, gettimeofday, monotonic, monotonic_raw 1151d5ac70f0Sopenharmony_ci slave STR 1152d5ac70f0Sopenharmony_ci # or 1153d5ac70f0Sopenharmony_ci slave { # Slave definition 1154d5ac70f0Sopenharmony_ci pcm STR # slave PCM name 1155d5ac70f0Sopenharmony_ci # or 1156d5ac70f0Sopenharmony_ci pcm { } # slave PCM definition 1157d5ac70f0Sopenharmony_ci format STR # format definition 1158d5ac70f0Sopenharmony_ci rate INT # rate definition 1159d5ac70f0Sopenharmony_ci channels INT 1160d5ac70f0Sopenharmony_ci period_time INT # in usec 1161d5ac70f0Sopenharmony_ci # or 1162d5ac70f0Sopenharmony_ci period_size INT # in frames 1163d5ac70f0Sopenharmony_ci buffer_time INT # in usec 1164d5ac70f0Sopenharmony_ci # or 1165d5ac70f0Sopenharmony_ci buffer_size INT # in frames 1166d5ac70f0Sopenharmony_ci periods INT # when buffer_size or buffer_time is not specified 1167d5ac70f0Sopenharmony_ci } 1168d5ac70f0Sopenharmony_ci bindings { # note: this is client independent!!! 1169d5ac70f0Sopenharmony_ci N INT # maps slave channel to client channel N 1170d5ac70f0Sopenharmony_ci } 1171d5ac70f0Sopenharmony_ci slowptr BOOL # slow but more precise pointer updates 1172d5ac70f0Sopenharmony_ci} 1173d5ac70f0Sopenharmony_ci\endcode 1174d5ac70f0Sopenharmony_ci 1175d5ac70f0Sopenharmony_ci<code>ipc_key</code> specfies the unique IPC key in integer. 1176d5ac70f0Sopenharmony_ciThis number must be unique for each different dmix definition, 1177d5ac70f0Sopenharmony_cisince the shared memory is created with this key number. 1178d5ac70f0Sopenharmony_ciWhen <code>ipc_key_add_uid</code> is set true, the uid value is 1179d5ac70f0Sopenharmony_ciadded to the value set in <code>ipc_key</code>. This will 1180d5ac70f0Sopenharmony_ciavoid the confliction of the same IPC key with different users 1181d5ac70f0Sopenharmony_ciconcurrently. 1182d5ac70f0Sopenharmony_ci 1183d5ac70f0Sopenharmony_ci<code>hw_ptr_alignment</code> specifies slave application and hw 1184d5ac70f0Sopenharmony_cipointer alignment type. By default hw_ptr_alignment is auto. Below are 1185d5ac70f0Sopenharmony_cithe possible configurations: 1186d5ac70f0Sopenharmony_ci- no: minimal latency with minimal frames dropped at startup. But 1187d5ac70f0Sopenharmony_ci wakeup of application (return from snd_pcm_wait() or poll()) can 1188d5ac70f0Sopenharmony_ci take up to 2 * period. 1189d5ac70f0Sopenharmony_ci- roundup: It is guaranteed that all frames will be played at 1190d5ac70f0Sopenharmony_ci startup. But the latency will increase upto period-1 frames. 1191d5ac70f0Sopenharmony_ci- rounddown: It is guaranteed that a wakeup will happen for each 1192d5ac70f0Sopenharmony_ci period and frames can be written from application. But on startup 1193d5ac70f0Sopenharmony_ci upto period-1 frames will be dropped. 1194d5ac70f0Sopenharmony_ci- auto: Selects the best approach depending on the used period and 1195d5ac70f0Sopenharmony_ci buffer size. 1196d5ac70f0Sopenharmony_ci If the application buffer size is < 2 * application period, 1197d5ac70f0Sopenharmony_ci "roundup" will be selected to avoid under runs. If the slave_period 1198d5ac70f0Sopenharmony_ci is < 10ms we could expect that there are low latency 1199d5ac70f0Sopenharmony_ci requirements. Therefore "rounddown" will be chosen to avoid long 1200d5ac70f0Sopenharmony_ci wakeup times. Such wakeup delay could otherwise end up with Xruns in 1201d5ac70f0Sopenharmony_ci case of a dependency to another sound device (e.g. forwarding of 1202d5ac70f0Sopenharmony_ci microphone to speaker). Else "no" will be chosen. 1203d5ac70f0Sopenharmony_ci 1204d5ac70f0Sopenharmony_ciNote that the dmix plugin itself supports only a single configuration. 1205d5ac70f0Sopenharmony_ciThat is, it supports only the fixed rate (default 48000), format 1206d5ac70f0Sopenharmony_ci(\c S16), channels (2), and period_time (125000). 1207d5ac70f0Sopenharmony_ciFor using other configuration, you have to set the value explicitly 1208d5ac70f0Sopenharmony_ciin the slave PCM definition. The rate, format and channels can be 1209d5ac70f0Sopenharmony_cicovered by an additional \ref pcm_plugins_dmix "plug plugin", 1210d5ac70f0Sopenharmony_cibut there is only one base configuration, anyway. 1211d5ac70f0Sopenharmony_ci 1212d5ac70f0Sopenharmony_ciAn example configuration for setting 44100 Hz, \c S32_LE format 1213d5ac70f0Sopenharmony_cias the slave PCM of "hw:0" is like below: 1214d5ac70f0Sopenharmony_ci\code 1215d5ac70f0Sopenharmony_cipcm.dmix_44 { 1216d5ac70f0Sopenharmony_ci type dmix 1217d5ac70f0Sopenharmony_ci ipc_key 321456 # any unique value 1218d5ac70f0Sopenharmony_ci ipc_key_add_uid true 1219d5ac70f0Sopenharmony_ci slave { 1220d5ac70f0Sopenharmony_ci pcm "hw:0" 1221d5ac70f0Sopenharmony_ci format S32_LE 1222d5ac70f0Sopenharmony_ci rate 44100 1223d5ac70f0Sopenharmony_ci } 1224d5ac70f0Sopenharmony_ci} 1225d5ac70f0Sopenharmony_ci\endcode 1226d5ac70f0Sopenharmony_ciYou can hear 48000 Hz samples still using this dmix pcm via plug plugin 1227d5ac70f0Sopenharmony_cilike: 1228d5ac70f0Sopenharmony_ci\code 1229d5ac70f0Sopenharmony_ci% aplay -Dplug:dmix_44 foo_48k.wav 1230d5ac70f0Sopenharmony_ci\endcode 1231d5ac70f0Sopenharmony_ci 1232d5ac70f0Sopenharmony_ciFor using the dmix plugin for OSS emulation device, you have to set 1233d5ac70f0Sopenharmony_cithe period and the buffer sizes in power of two. For example, 1234d5ac70f0Sopenharmony_ci\code 1235d5ac70f0Sopenharmony_cipcm.dmixoss { 1236d5ac70f0Sopenharmony_ci type dmix 1237d5ac70f0Sopenharmony_ci ipc_key 321456 # any unique value 1238d5ac70f0Sopenharmony_ci ipc_key_add_uid true 1239d5ac70f0Sopenharmony_ci slave { 1240d5ac70f0Sopenharmony_ci pcm "hw:0" 1241d5ac70f0Sopenharmony_ci period_time 0 1242d5ac70f0Sopenharmony_ci period_size 1024 # must be power of 2 1243d5ac70f0Sopenharmony_ci buffer_size 8192 # ditto 1244d5ac70f0Sopenharmony_ci } 1245d5ac70f0Sopenharmony_ci} 1246d5ac70f0Sopenharmony_ci\endcode 1247d5ac70f0Sopenharmony_ci<code>period_time 0</code> must be set, too, for resetting the 1248d5ac70f0Sopenharmony_cidefault value. In the case of soundcards with multi-channel IO, 1249d5ac70f0Sopenharmony_ciadding the bindings would help 1250d5ac70f0Sopenharmony_ci\code 1251d5ac70f0Sopenharmony_cipcm.dmixoss { 1252d5ac70f0Sopenharmony_ci ... 1253d5ac70f0Sopenharmony_ci bindings { 1254d5ac70f0Sopenharmony_ci 0 0 # map from 0 to 0 1255d5ac70f0Sopenharmony_ci 1 1 # map from 1 to 1 1256d5ac70f0Sopenharmony_ci } 1257d5ac70f0Sopenharmony_ci} 1258d5ac70f0Sopenharmony_ci\endcode 1259d5ac70f0Sopenharmony_ciso that only the first two channels are used by dmix. 1260d5ac70f0Sopenharmony_ciAlso, note that ICE1712 have the limited buffer size, 5513 frames 1261d5ac70f0Sopenharmony_ci(corresponding to 640 kB). In this case, reduce the buffer_size 1262d5ac70f0Sopenharmony_cito 4096. 1263d5ac70f0Sopenharmony_ci 1264d5ac70f0Sopenharmony_ci\subsection pcm_plugins_dmix_funcref Function reference 1265d5ac70f0Sopenharmony_ci 1266d5ac70f0Sopenharmony_ci<UL> 1267d5ac70f0Sopenharmony_ci <LI>snd_pcm_dmix_open() 1268d5ac70f0Sopenharmony_ci <LI>_snd_pcm_dmix_open() 1269d5ac70f0Sopenharmony_ci</UL> 1270d5ac70f0Sopenharmony_ci 1271d5ac70f0Sopenharmony_ci*/ 1272d5ac70f0Sopenharmony_ci 1273d5ac70f0Sopenharmony_ci/** 1274d5ac70f0Sopenharmony_ci * \brief Creates a new dmix PCM 1275d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 1276d5ac70f0Sopenharmony_ci * \param name Name of PCM 1277d5ac70f0Sopenharmony_ci * \param root Root configuration node 1278d5ac70f0Sopenharmony_ci * \param conf Configuration node with dmix PCM description 1279d5ac70f0Sopenharmony_ci * \param stream PCM Stream 1280d5ac70f0Sopenharmony_ci * \param mode PCM Mode 1281d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 1282d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 1283d5ac70f0Sopenharmony_ci * changed in future. 1284d5ac70f0Sopenharmony_ci */ 1285d5ac70f0Sopenharmony_ciint _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, 1286d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *conf, 1287d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 1288d5ac70f0Sopenharmony_ci{ 1289d5ac70f0Sopenharmony_ci snd_config_t *sconf; 1290d5ac70f0Sopenharmony_ci struct slave_params params; 1291d5ac70f0Sopenharmony_ci struct snd_pcm_direct_open_conf dopen; 1292d5ac70f0Sopenharmony_ci int bsize, psize; 1293d5ac70f0Sopenharmony_ci int err; 1294d5ac70f0Sopenharmony_ci 1295d5ac70f0Sopenharmony_ci err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen); 1296d5ac70f0Sopenharmony_ci if (err < 0) 1297d5ac70f0Sopenharmony_ci return err; 1298d5ac70f0Sopenharmony_ci 1299d5ac70f0Sopenharmony_ci /* the default settings, it might be invalid for some hardware */ 1300d5ac70f0Sopenharmony_ci params.format = SND_PCM_FORMAT_S16; 1301d5ac70f0Sopenharmony_ci params.rate = 48000; 1302d5ac70f0Sopenharmony_ci params.channels = 2; 1303d5ac70f0Sopenharmony_ci params.period_time = -1; 1304d5ac70f0Sopenharmony_ci params.buffer_time = -1; 1305d5ac70f0Sopenharmony_ci bsize = psize = -1; 1306d5ac70f0Sopenharmony_ci params.periods = 3; 1307d5ac70f0Sopenharmony_ci 1308d5ac70f0Sopenharmony_ci err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8, 1309d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format, 1310d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate, 1311d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels, 1312d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time, 1313d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time, 1314d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize, 1315d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize, 1316d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods); 1317d5ac70f0Sopenharmony_ci if (err < 0) 1318d5ac70f0Sopenharmony_ci return err; 1319d5ac70f0Sopenharmony_ci 1320d5ac70f0Sopenharmony_ci /* set a reasonable default */ 1321d5ac70f0Sopenharmony_ci if (psize == -1 && params.period_time == -1) 1322d5ac70f0Sopenharmony_ci params.period_time = 125000; /* 0.125 seconds */ 1323d5ac70f0Sopenharmony_ci 1324d5ac70f0Sopenharmony_ci if (params.format == -2) 1325d5ac70f0Sopenharmony_ci params.format = SND_PCM_FORMAT_UNKNOWN; 1326d5ac70f0Sopenharmony_ci else if (!(dmix_supported_format & (1ULL << params.format))) { 1327d5ac70f0Sopenharmony_ci /* sorry, limited features */ 1328d5ac70f0Sopenharmony_ci SNDERR("Unsupported format"); 1329d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 1330d5ac70f0Sopenharmony_ci return -EINVAL; 1331d5ac70f0Sopenharmony_ci } 1332d5ac70f0Sopenharmony_ci 1333d5ac70f0Sopenharmony_ci params.period_size = psize; 1334d5ac70f0Sopenharmony_ci params.buffer_size = bsize; 1335d5ac70f0Sopenharmony_ci 1336d5ac70f0Sopenharmony_ci err = snd_pcm_dmix_open(pcmp, name, &dopen, ¶ms, 1337d5ac70f0Sopenharmony_ci root, sconf, stream, mode); 1338d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 1339d5ac70f0Sopenharmony_ci return err; 1340d5ac70f0Sopenharmony_ci} 1341d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 1342d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_dmix_open, SND_PCM_DLSYM_VERSION); 1343d5ac70f0Sopenharmony_ci#endif 1344