1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_dshare.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM_Plugins 4d5ac70f0Sopenharmony_ci * \brief PCM Direct Sharing of Channels Plugin Interface 5d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 6d5ac70f0Sopenharmony_ci * \date 2003 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * PCM - Direct Sharing of Channels 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_dshare = ""; 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_cistatic void do_silence(snd_pcm_t *pcm) 60d5ac70f0Sopenharmony_ci{ 61d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 62d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *dst_areas; 63d5ac70f0Sopenharmony_ci unsigned int chn, dchn, channels; 64d5ac70f0Sopenharmony_ci snd_pcm_format_t format; 65d5ac70f0Sopenharmony_ci 66d5ac70f0Sopenharmony_ci dst_areas = snd_pcm_mmap_areas(dshare->spcm); 67d5ac70f0Sopenharmony_ci channels = dshare->channels; 68d5ac70f0Sopenharmony_ci format = dshare->shmptr->s.format; 69d5ac70f0Sopenharmony_ci for (chn = 0; chn < channels; chn++) { 70d5ac70f0Sopenharmony_ci dchn = dshare->bindings ? dshare->bindings[chn] : chn; 71d5ac70f0Sopenharmony_ci if (dchn != UINT_MAX) 72d5ac70f0Sopenharmony_ci snd_pcm_area_silence(&dst_areas[dchn], 0, 73d5ac70f0Sopenharmony_ci dshare->shmptr->s.buffer_size, format); 74d5ac70f0Sopenharmony_ci } 75d5ac70f0Sopenharmony_ci} 76d5ac70f0Sopenharmony_ci 77d5ac70f0Sopenharmony_cistatic void share_areas(snd_pcm_direct_t *dshare, 78d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, 79d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *dst_areas, 80d5ac70f0Sopenharmony_ci snd_pcm_uframes_t src_ofs, 81d5ac70f0Sopenharmony_ci snd_pcm_uframes_t dst_ofs, 82d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 83d5ac70f0Sopenharmony_ci{ 84d5ac70f0Sopenharmony_ci unsigned int chn, dchn, channels; 85d5ac70f0Sopenharmony_ci snd_pcm_format_t format; 86d5ac70f0Sopenharmony_ci 87d5ac70f0Sopenharmony_ci channels = dshare->channels; 88d5ac70f0Sopenharmony_ci format = dshare->shmptr->s.format; 89d5ac70f0Sopenharmony_ci if (dshare->interleaved) { 90d5ac70f0Sopenharmony_ci unsigned int fbytes = snd_pcm_format_physical_width(format) / 8; 91d5ac70f0Sopenharmony_ci memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes), 92d5ac70f0Sopenharmony_ci ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes), 93d5ac70f0Sopenharmony_ci size * channels * fbytes); 94d5ac70f0Sopenharmony_ci } else { 95d5ac70f0Sopenharmony_ci for (chn = 0; chn < channels; chn++) { 96d5ac70f0Sopenharmony_ci dchn = dshare->bindings ? dshare->bindings[chn] : chn; 97d5ac70f0Sopenharmony_ci if (dchn != UINT_MAX) 98d5ac70f0Sopenharmony_ci snd_pcm_area_copy(&dst_areas[dchn], dst_ofs, 99d5ac70f0Sopenharmony_ci &src_areas[chn], src_ofs, size, format); 100d5ac70f0Sopenharmony_ci 101d5ac70f0Sopenharmony_ci } 102d5ac70f0Sopenharmony_ci } 103d5ac70f0Sopenharmony_ci} 104d5ac70f0Sopenharmony_ci 105d5ac70f0Sopenharmony_ci/* 106d5ac70f0Sopenharmony_ci * synchronize shm ring buffer with hardware 107d5ac70f0Sopenharmony_ci */ 108d5ac70f0Sopenharmony_cistatic void snd_pcm_dshare_sync_area(snd_pcm_t *pcm) 109d5ac70f0Sopenharmony_ci{ 110d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 111d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_hw_ptr, slave_appl_ptr, slave_size; 112d5ac70f0Sopenharmony_ci snd_pcm_uframes_t appl_ptr, size; 113d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, *dst_areas; 114d5ac70f0Sopenharmony_ci 115d5ac70f0Sopenharmony_ci /* calculate the size to transfer */ 116d5ac70f0Sopenharmony_ci size = pcm_frame_diff(dshare->appl_ptr, dshare->last_appl_ptr, pcm->boundary); 117d5ac70f0Sopenharmony_ci if (! size) 118d5ac70f0Sopenharmony_ci return; 119d5ac70f0Sopenharmony_ci slave_hw_ptr = dshare->slave_hw_ptr; 120d5ac70f0Sopenharmony_ci /* don't write on the last active period - this area may be cleared 121d5ac70f0Sopenharmony_ci * by the driver during write operation... 122d5ac70f0Sopenharmony_ci */ 123d5ac70f0Sopenharmony_ci slave_hw_ptr -= slave_hw_ptr % dshare->slave_period_size; 124d5ac70f0Sopenharmony_ci slave_hw_ptr += dshare->slave_buffer_size; 125d5ac70f0Sopenharmony_ci if (slave_hw_ptr >= dshare->slave_boundary) 126d5ac70f0Sopenharmony_ci slave_hw_ptr -= dshare->slave_boundary; 127d5ac70f0Sopenharmony_ci slave_size = pcm_frame_diff(slave_hw_ptr, dshare->slave_appl_ptr, dshare->slave_boundary); 128d5ac70f0Sopenharmony_ci if (slave_size < size) 129d5ac70f0Sopenharmony_ci size = slave_size; 130d5ac70f0Sopenharmony_ci if (! size) 131d5ac70f0Sopenharmony_ci return; 132d5ac70f0Sopenharmony_ci 133d5ac70f0Sopenharmony_ci /* add sample areas here */ 134d5ac70f0Sopenharmony_ci src_areas = snd_pcm_mmap_areas(pcm); 135d5ac70f0Sopenharmony_ci dst_areas = snd_pcm_mmap_areas(dshare->spcm); 136d5ac70f0Sopenharmony_ci appl_ptr = dshare->last_appl_ptr % pcm->buffer_size; 137d5ac70f0Sopenharmony_ci dshare->last_appl_ptr += size; 138d5ac70f0Sopenharmony_ci dshare->last_appl_ptr %= pcm->boundary; 139d5ac70f0Sopenharmony_ci slave_appl_ptr = dshare->slave_appl_ptr % dshare->slave_buffer_size; 140d5ac70f0Sopenharmony_ci dshare->slave_appl_ptr += size; 141d5ac70f0Sopenharmony_ci dshare->slave_appl_ptr %= dshare->slave_boundary; 142d5ac70f0Sopenharmony_ci for (;;) { 143d5ac70f0Sopenharmony_ci snd_pcm_uframes_t transfer = size; 144d5ac70f0Sopenharmony_ci if (appl_ptr + transfer > pcm->buffer_size) 145d5ac70f0Sopenharmony_ci transfer = pcm->buffer_size - appl_ptr; 146d5ac70f0Sopenharmony_ci if (slave_appl_ptr + transfer > dshare->slave_buffer_size) 147d5ac70f0Sopenharmony_ci transfer = dshare->slave_buffer_size - slave_appl_ptr; 148d5ac70f0Sopenharmony_ci share_areas(dshare, src_areas, dst_areas, appl_ptr, slave_appl_ptr, transfer); 149d5ac70f0Sopenharmony_ci size -= transfer; 150d5ac70f0Sopenharmony_ci if (! size) 151d5ac70f0Sopenharmony_ci break; 152d5ac70f0Sopenharmony_ci slave_appl_ptr += transfer; 153d5ac70f0Sopenharmony_ci slave_appl_ptr %= dshare->slave_buffer_size; 154d5ac70f0Sopenharmony_ci appl_ptr += transfer; 155d5ac70f0Sopenharmony_ci appl_ptr %= pcm->buffer_size; 156d5ac70f0Sopenharmony_ci } 157d5ac70f0Sopenharmony_ci} 158d5ac70f0Sopenharmony_ci 159d5ac70f0Sopenharmony_ci/* 160d5ac70f0Sopenharmony_ci * synchronize hardware pointer (hw_ptr) with ours 161d5ac70f0Sopenharmony_ci */ 162d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_sync_ptr0(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr) 163d5ac70f0Sopenharmony_ci{ 164d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 165d5ac70f0Sopenharmony_ci snd_pcm_uframes_t old_slave_hw_ptr, avail; 166d5ac70f0Sopenharmony_ci snd_pcm_sframes_t diff; 167d5ac70f0Sopenharmony_ci 168d5ac70f0Sopenharmony_ci old_slave_hw_ptr = dshare->slave_hw_ptr; 169d5ac70f0Sopenharmony_ci dshare->slave_hw_ptr = slave_hw_ptr; 170d5ac70f0Sopenharmony_ci diff = pcm_frame_diff(slave_hw_ptr, old_slave_hw_ptr, dshare->slave_boundary); 171d5ac70f0Sopenharmony_ci if (diff == 0) /* fast path */ 172d5ac70f0Sopenharmony_ci return 0; 173d5ac70f0Sopenharmony_ci if (dshare->state != SND_PCM_STATE_RUNNING && 174d5ac70f0Sopenharmony_ci dshare->state != SND_PCM_STATE_DRAINING) 175d5ac70f0Sopenharmony_ci /* not really started yet - don't update hw_ptr */ 176d5ac70f0Sopenharmony_ci return 0; 177d5ac70f0Sopenharmony_ci dshare->hw_ptr += diff; 178d5ac70f0Sopenharmony_ci dshare->hw_ptr %= pcm->boundary; 179d5ac70f0Sopenharmony_ci // printf("sync ptr diff = %li\n", diff); 180d5ac70f0Sopenharmony_ci if (pcm->stop_threshold >= pcm->boundary) /* don't care */ 181d5ac70f0Sopenharmony_ci return 0; 182d5ac70f0Sopenharmony_ci avail = snd_pcm_mmap_playback_avail(pcm); 183d5ac70f0Sopenharmony_ci if (avail > dshare->avail_max) 184d5ac70f0Sopenharmony_ci dshare->avail_max = avail; 185d5ac70f0Sopenharmony_ci if (avail >= pcm->stop_threshold) { 186d5ac70f0Sopenharmony_ci snd_timer_stop(dshare->timer); 187d5ac70f0Sopenharmony_ci do_silence(pcm); 188d5ac70f0Sopenharmony_ci gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type); 189d5ac70f0Sopenharmony_ci if (dshare->state == SND_PCM_STATE_RUNNING) { 190d5ac70f0Sopenharmony_ci dshare->state = SND_PCM_STATE_XRUN; 191d5ac70f0Sopenharmony_ci return -EPIPE; 192d5ac70f0Sopenharmony_ci } 193d5ac70f0Sopenharmony_ci dshare->state = SND_PCM_STATE_SETUP; 194d5ac70f0Sopenharmony_ci /* clear queue to remove pending poll events */ 195d5ac70f0Sopenharmony_ci snd_pcm_direct_clear_timer_queue(dshare); 196d5ac70f0Sopenharmony_ci } 197d5ac70f0Sopenharmony_ci return 0; 198d5ac70f0Sopenharmony_ci} 199d5ac70f0Sopenharmony_ci 200d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_sync_ptr(snd_pcm_t *pcm) 201d5ac70f0Sopenharmony_ci{ 202d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 203d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_hw_ptr; 204d5ac70f0Sopenharmony_ci int err; 205d5ac70f0Sopenharmony_ci 206d5ac70f0Sopenharmony_ci if (dshare->slowptr) 207d5ac70f0Sopenharmony_ci snd_pcm_hwsync(dshare->spcm); 208d5ac70f0Sopenharmony_ci slave_hw_ptr = *dshare->spcm->hw.ptr; 209d5ac70f0Sopenharmony_ci err = snd_pcm_direct_check_xrun(dshare, pcm); 210d5ac70f0Sopenharmony_ci if (err < 0) 211d5ac70f0Sopenharmony_ci return err; 212d5ac70f0Sopenharmony_ci 213d5ac70f0Sopenharmony_ci return snd_pcm_dshare_sync_ptr0(pcm, slave_hw_ptr); 214d5ac70f0Sopenharmony_ci} 215d5ac70f0Sopenharmony_ci 216d5ac70f0Sopenharmony_ci/* 217d5ac70f0Sopenharmony_ci * plugin implementation 218d5ac70f0Sopenharmony_ci */ 219d5ac70f0Sopenharmony_ci 220d5ac70f0Sopenharmony_cistatic snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm); 221d5ac70f0Sopenharmony_ci 222d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_status(snd_pcm_t *pcm, snd_pcm_status_t * status) 223d5ac70f0Sopenharmony_ci{ 224d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 225d5ac70f0Sopenharmony_ci 226d5ac70f0Sopenharmony_ci memset(status, 0, sizeof(*status)); 227d5ac70f0Sopenharmony_ci snd_pcm_status(dshare->spcm, status); 228d5ac70f0Sopenharmony_ci 229d5ac70f0Sopenharmony_ci switch (dshare->state) { 230d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DRAINING: 231d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 232d5ac70f0Sopenharmony_ci snd_pcm_dshare_sync_ptr0(pcm, status->hw_ptr); 233d5ac70f0Sopenharmony_ci status->delay = snd_pcm_mmap_playback_delay(pcm); 234d5ac70f0Sopenharmony_ci break; 235d5ac70f0Sopenharmony_ci default: 236d5ac70f0Sopenharmony_ci break; 237d5ac70f0Sopenharmony_ci } 238d5ac70f0Sopenharmony_ci status->state = snd_pcm_dshare_state(pcm); 239d5ac70f0Sopenharmony_ci status->hw_ptr = *pcm->hw.ptr; /* boundary may be different */ 240d5ac70f0Sopenharmony_ci status->appl_ptr = *pcm->appl.ptr; /* slave PCM doesn't set appl_ptr */ 241d5ac70f0Sopenharmony_ci status->trigger_tstamp = dshare->trigger_tstamp; 242d5ac70f0Sopenharmony_ci status->avail = snd_pcm_mmap_playback_avail(pcm); 243d5ac70f0Sopenharmony_ci status->avail_max = status->avail > dshare->avail_max ? status->avail : dshare->avail_max; 244d5ac70f0Sopenharmony_ci dshare->avail_max = 0; 245d5ac70f0Sopenharmony_ci return 0; 246d5ac70f0Sopenharmony_ci} 247d5ac70f0Sopenharmony_ci 248d5ac70f0Sopenharmony_cistatic snd_pcm_state_t snd_pcm_dshare_state(snd_pcm_t *pcm) 249d5ac70f0Sopenharmony_ci{ 250d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 251d5ac70f0Sopenharmony_ci 252d5ac70f0Sopenharmony_ci snd_pcm_direct_check_xrun(dshare, pcm); 253d5ac70f0Sopenharmony_ci if (dshare->state == STATE_RUN_PENDING) 254d5ac70f0Sopenharmony_ci return SNDRV_PCM_STATE_RUNNING; 255d5ac70f0Sopenharmony_ci return dshare->state; 256d5ac70f0Sopenharmony_ci} 257d5ac70f0Sopenharmony_ci 258d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 259d5ac70f0Sopenharmony_ci{ 260d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 261d5ac70f0Sopenharmony_ci int err; 262d5ac70f0Sopenharmony_ci 263d5ac70f0Sopenharmony_ci switch (dshare->state) { 264d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DRAINING: 265d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 266d5ac70f0Sopenharmony_ci err = snd_pcm_dshare_sync_ptr(pcm); 267d5ac70f0Sopenharmony_ci if (err < 0) 268d5ac70f0Sopenharmony_ci return err; 269d5ac70f0Sopenharmony_ci /* fallthru */ 270d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_PREPARED: 271d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_SUSPENDED: 272d5ac70f0Sopenharmony_ci case STATE_RUN_PENDING: 273d5ac70f0Sopenharmony_ci *delayp = snd_pcm_mmap_playback_delay(pcm); 274d5ac70f0Sopenharmony_ci return 0; 275d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_XRUN: 276d5ac70f0Sopenharmony_ci return -EPIPE; 277d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DISCONNECTED: 278d5ac70f0Sopenharmony_ci return -ENODEV; 279d5ac70f0Sopenharmony_ci default: 280d5ac70f0Sopenharmony_ci return -EBADFD; 281d5ac70f0Sopenharmony_ci } 282d5ac70f0Sopenharmony_ci} 283d5ac70f0Sopenharmony_ci 284d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_hwsync(snd_pcm_t *pcm) 285d5ac70f0Sopenharmony_ci{ 286d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 287d5ac70f0Sopenharmony_ci 288d5ac70f0Sopenharmony_ci switch(dshare->state) { 289d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DRAINING: 290d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 291d5ac70f0Sopenharmony_ci return snd_pcm_dshare_sync_ptr(pcm); 292d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_PREPARED: 293d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_SUSPENDED: 294d5ac70f0Sopenharmony_ci return 0; 295d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_XRUN: 296d5ac70f0Sopenharmony_ci return -EPIPE; 297d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DISCONNECTED: 298d5ac70f0Sopenharmony_ci return -ENODEV; 299d5ac70f0Sopenharmony_ci default: 300d5ac70f0Sopenharmony_ci return -EBADFD; 301d5ac70f0Sopenharmony_ci } 302d5ac70f0Sopenharmony_ci} 303d5ac70f0Sopenharmony_ci 304d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_reset(snd_pcm_t *pcm) 305d5ac70f0Sopenharmony_ci{ 306d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 307d5ac70f0Sopenharmony_ci dshare->hw_ptr %= pcm->period_size; 308d5ac70f0Sopenharmony_ci dshare->appl_ptr = dshare->last_appl_ptr = dshare->hw_ptr; 309d5ac70f0Sopenharmony_ci snd_pcm_direct_reset_slave_ptr(pcm, dshare, *dshare->spcm->hw.ptr); 310d5ac70f0Sopenharmony_ci return 0; 311d5ac70f0Sopenharmony_ci} 312d5ac70f0Sopenharmony_ci 313d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_start_timer(snd_pcm_t *pcm, snd_pcm_direct_t *dshare) 314d5ac70f0Sopenharmony_ci{ 315d5ac70f0Sopenharmony_ci int err; 316d5ac70f0Sopenharmony_ci 317d5ac70f0Sopenharmony_ci snd_pcm_hwsync(dshare->spcm); 318d5ac70f0Sopenharmony_ci snd_pcm_direct_reset_slave_ptr(pcm, dshare, *dshare->spcm->hw.ptr); 319d5ac70f0Sopenharmony_ci err = snd_timer_start(dshare->timer); 320d5ac70f0Sopenharmony_ci if (err < 0) 321d5ac70f0Sopenharmony_ci return err; 322d5ac70f0Sopenharmony_ci dshare->state = SND_PCM_STATE_RUNNING; 323d5ac70f0Sopenharmony_ci return 0; 324d5ac70f0Sopenharmony_ci} 325d5ac70f0Sopenharmony_ci 326d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_start(snd_pcm_t *pcm) 327d5ac70f0Sopenharmony_ci{ 328d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 329d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail; 330d5ac70f0Sopenharmony_ci int err; 331d5ac70f0Sopenharmony_ci 332d5ac70f0Sopenharmony_ci if (dshare->state != SND_PCM_STATE_PREPARED) 333d5ac70f0Sopenharmony_ci return -EBADFD; 334d5ac70f0Sopenharmony_ci avail = snd_pcm_mmap_playback_hw_avail(pcm); 335d5ac70f0Sopenharmony_ci if (avail == 0) 336d5ac70f0Sopenharmony_ci dshare->state = STATE_RUN_PENDING; 337d5ac70f0Sopenharmony_ci else if (avail < 0) 338d5ac70f0Sopenharmony_ci return 0; 339d5ac70f0Sopenharmony_ci else { 340d5ac70f0Sopenharmony_ci err = snd_pcm_dshare_start_timer(pcm, dshare); 341d5ac70f0Sopenharmony_ci if (err < 0) 342d5ac70f0Sopenharmony_ci return err; 343d5ac70f0Sopenharmony_ci snd_pcm_dshare_sync_area(pcm); 344d5ac70f0Sopenharmony_ci } 345d5ac70f0Sopenharmony_ci gettimestamp(&dshare->trigger_tstamp, pcm->tstamp_type); 346d5ac70f0Sopenharmony_ci return 0; 347d5ac70f0Sopenharmony_ci} 348d5ac70f0Sopenharmony_ci 349d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_drop(snd_pcm_t *pcm) 350d5ac70f0Sopenharmony_ci{ 351d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 352d5ac70f0Sopenharmony_ci if (dshare->state == SND_PCM_STATE_OPEN) 353d5ac70f0Sopenharmony_ci return -EBADFD; 354d5ac70f0Sopenharmony_ci dshare->state = SND_PCM_STATE_SETUP; 355d5ac70f0Sopenharmony_ci snd_pcm_direct_timer_stop(dshare); 356d5ac70f0Sopenharmony_ci do_silence(pcm); 357d5ac70f0Sopenharmony_ci return 0; 358d5ac70f0Sopenharmony_ci} 359d5ac70f0Sopenharmony_ci 360d5ac70f0Sopenharmony_ci/* locked version */ 361d5ac70f0Sopenharmony_cistatic int __snd_pcm_dshare_drain(snd_pcm_t *pcm) 362d5ac70f0Sopenharmony_ci{ 363d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 364d5ac70f0Sopenharmony_ci snd_pcm_uframes_t stop_threshold; 365d5ac70f0Sopenharmony_ci int err; 366d5ac70f0Sopenharmony_ci 367d5ac70f0Sopenharmony_ci switch (snd_pcm_state(dshare->spcm)) { 368d5ac70f0Sopenharmony_ci case SND_PCM_STATE_SUSPENDED: 369d5ac70f0Sopenharmony_ci return -ESTRPIPE; 370d5ac70f0Sopenharmony_ci default: 371d5ac70f0Sopenharmony_ci break; 372d5ac70f0Sopenharmony_ci } 373d5ac70f0Sopenharmony_ci 374d5ac70f0Sopenharmony_ci if (dshare->state == SND_PCM_STATE_OPEN) 375d5ac70f0Sopenharmony_ci return -EBADFD; 376d5ac70f0Sopenharmony_ci if (pcm->mode & SND_PCM_NONBLOCK) 377d5ac70f0Sopenharmony_ci return -EAGAIN; 378d5ac70f0Sopenharmony_ci if (dshare->state == SND_PCM_STATE_PREPARED) { 379d5ac70f0Sopenharmony_ci if (snd_pcm_mmap_playback_hw_avail(pcm) > 0) 380d5ac70f0Sopenharmony_ci snd_pcm_dshare_start(pcm); 381d5ac70f0Sopenharmony_ci else { 382d5ac70f0Sopenharmony_ci snd_pcm_dshare_drop(pcm); 383d5ac70f0Sopenharmony_ci return 0; 384d5ac70f0Sopenharmony_ci } 385d5ac70f0Sopenharmony_ci } 386d5ac70f0Sopenharmony_ci 387d5ac70f0Sopenharmony_ci if (dshare->state == SND_PCM_STATE_XRUN) { 388d5ac70f0Sopenharmony_ci snd_pcm_dshare_drop(pcm); 389d5ac70f0Sopenharmony_ci return 0; 390d5ac70f0Sopenharmony_ci } 391d5ac70f0Sopenharmony_ci 392d5ac70f0Sopenharmony_ci stop_threshold = pcm->stop_threshold; 393d5ac70f0Sopenharmony_ci if (pcm->stop_threshold > pcm->buffer_size) 394d5ac70f0Sopenharmony_ci pcm->stop_threshold = pcm->buffer_size; 395d5ac70f0Sopenharmony_ci dshare->state = SND_PCM_STATE_DRAINING; 396d5ac70f0Sopenharmony_ci do { 397d5ac70f0Sopenharmony_ci err = snd_pcm_dshare_sync_ptr(pcm); 398d5ac70f0Sopenharmony_ci if (err < 0) { 399d5ac70f0Sopenharmony_ci snd_pcm_dshare_drop(pcm); 400d5ac70f0Sopenharmony_ci break; 401d5ac70f0Sopenharmony_ci } 402d5ac70f0Sopenharmony_ci if (dshare->state == SND_PCM_STATE_DRAINING) { 403d5ac70f0Sopenharmony_ci snd_pcm_dshare_sync_area(pcm); 404d5ac70f0Sopenharmony_ci snd_pcm_wait_nocheck(pcm, SND_PCM_WAIT_DRAIN); 405d5ac70f0Sopenharmony_ci snd_pcm_direct_clear_timer_queue(dshare); /* force poll to wait */ 406d5ac70f0Sopenharmony_ci 407d5ac70f0Sopenharmony_ci switch (snd_pcm_state(dshare->spcm)) { 408d5ac70f0Sopenharmony_ci case SND_PCM_STATE_SUSPENDED: 409d5ac70f0Sopenharmony_ci return -ESTRPIPE; 410d5ac70f0Sopenharmony_ci default: 411d5ac70f0Sopenharmony_ci break; 412d5ac70f0Sopenharmony_ci } 413d5ac70f0Sopenharmony_ci } 414d5ac70f0Sopenharmony_ci } while (dshare->state == SND_PCM_STATE_DRAINING); 415d5ac70f0Sopenharmony_ci pcm->stop_threshold = stop_threshold; 416d5ac70f0Sopenharmony_ci return 0; 417d5ac70f0Sopenharmony_ci} 418d5ac70f0Sopenharmony_ci 419d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_drain(snd_pcm_t *pcm) 420d5ac70f0Sopenharmony_ci{ 421d5ac70f0Sopenharmony_ci int err; 422d5ac70f0Sopenharmony_ci 423d5ac70f0Sopenharmony_ci snd_pcm_lock(pcm); 424d5ac70f0Sopenharmony_ci err = __snd_pcm_dshare_drain(pcm); 425d5ac70f0Sopenharmony_ci snd_pcm_unlock(pcm); 426d5ac70f0Sopenharmony_ci return err; 427d5ac70f0Sopenharmony_ci} 428d5ac70f0Sopenharmony_ci 429d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED) 430d5ac70f0Sopenharmony_ci{ 431d5ac70f0Sopenharmony_ci return -EIO; 432d5ac70f0Sopenharmony_ci} 433d5ac70f0Sopenharmony_ci 434d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_rewindable(snd_pcm_t *pcm) 435d5ac70f0Sopenharmony_ci{ 436d5ac70f0Sopenharmony_ci return snd_pcm_mmap_playback_hw_rewindable(pcm); 437d5ac70f0Sopenharmony_ci} 438d5ac70f0Sopenharmony_ci 439d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 440d5ac70f0Sopenharmony_ci{ 441d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail; 442d5ac70f0Sopenharmony_ci 443d5ac70f0Sopenharmony_ci avail = snd_pcm_dshare_rewindable(pcm); 444d5ac70f0Sopenharmony_ci if (frames > (snd_pcm_uframes_t)avail) 445d5ac70f0Sopenharmony_ci frames = avail; 446d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_backward(pcm, frames); 447d5ac70f0Sopenharmony_ci return frames; 448d5ac70f0Sopenharmony_ci} 449d5ac70f0Sopenharmony_ci 450d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_forwardable(snd_pcm_t *pcm) 451d5ac70f0Sopenharmony_ci{ 452d5ac70f0Sopenharmony_ci return snd_pcm_mmap_playback_avail(pcm); 453d5ac70f0Sopenharmony_ci} 454d5ac70f0Sopenharmony_ci 455d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 456d5ac70f0Sopenharmony_ci{ 457d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail; 458d5ac70f0Sopenharmony_ci 459d5ac70f0Sopenharmony_ci avail = snd_pcm_dshare_forwardable(pcm); 460d5ac70f0Sopenharmony_ci if (frames > (snd_pcm_uframes_t)avail) 461d5ac70f0Sopenharmony_ci frames = avail; 462d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, frames); 463d5ac70f0Sopenharmony_ci return frames; 464d5ac70f0Sopenharmony_ci} 465d5ac70f0Sopenharmony_ci 466d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) 467d5ac70f0Sopenharmony_ci{ 468d5ac70f0Sopenharmony_ci return -ENODEV; 469d5ac70f0Sopenharmony_ci} 470d5ac70f0Sopenharmony_ci 471d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_readn(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) 472d5ac70f0Sopenharmony_ci{ 473d5ac70f0Sopenharmony_ci return -ENODEV; 474d5ac70f0Sopenharmony_ci} 475d5ac70f0Sopenharmony_ci 476d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_close(snd_pcm_t *pcm) 477d5ac70f0Sopenharmony_ci{ 478d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 479d5ac70f0Sopenharmony_ci 480d5ac70f0Sopenharmony_ci if (dshare->timer) 481d5ac70f0Sopenharmony_ci snd_timer_close(dshare->timer); 482d5ac70f0Sopenharmony_ci if (dshare->bindings) 483d5ac70f0Sopenharmony_ci do_silence(pcm); 484d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT); 485d5ac70f0Sopenharmony_ci dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask; 486d5ac70f0Sopenharmony_ci snd_pcm_close(dshare->spcm); 487d5ac70f0Sopenharmony_ci if (dshare->server) 488d5ac70f0Sopenharmony_ci snd_pcm_direct_server_discard(dshare); 489d5ac70f0Sopenharmony_ci if (dshare->client) 490d5ac70f0Sopenharmony_ci snd_pcm_direct_client_discard(dshare); 491d5ac70f0Sopenharmony_ci if (snd_pcm_direct_shm_discard(dshare)) { 492d5ac70f0Sopenharmony_ci if (snd_pcm_direct_semaphore_discard(dshare)) 493d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT); 494d5ac70f0Sopenharmony_ci } else 495d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT); 496d5ac70f0Sopenharmony_ci free(dshare->bindings); 497d5ac70f0Sopenharmony_ci pcm->private_data = NULL; 498d5ac70f0Sopenharmony_ci free(dshare); 499d5ac70f0Sopenharmony_ci return 0; 500d5ac70f0Sopenharmony_ci} 501d5ac70f0Sopenharmony_ci 502d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_mmap_commit(snd_pcm_t *pcm, 503d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, 504d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 505d5ac70f0Sopenharmony_ci{ 506d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 507d5ac70f0Sopenharmony_ci int err; 508d5ac70f0Sopenharmony_ci 509d5ac70f0Sopenharmony_ci err = snd_pcm_direct_check_xrun(dshare, pcm); 510d5ac70f0Sopenharmony_ci if (err < 0) 511d5ac70f0Sopenharmony_ci return err; 512d5ac70f0Sopenharmony_ci if (! size) 513d5ac70f0Sopenharmony_ci return 0; 514d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, size); 515d5ac70f0Sopenharmony_ci if (dshare->state == STATE_RUN_PENDING) { 516d5ac70f0Sopenharmony_ci err = snd_pcm_dshare_start_timer(pcm, dshare); 517d5ac70f0Sopenharmony_ci if (err < 0) 518d5ac70f0Sopenharmony_ci return err; 519d5ac70f0Sopenharmony_ci } else if (dshare->state == SND_PCM_STATE_RUNNING || 520d5ac70f0Sopenharmony_ci dshare->state == SND_PCM_STATE_DRAINING) { 521d5ac70f0Sopenharmony_ci if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0) 522d5ac70f0Sopenharmony_ci return err; 523d5ac70f0Sopenharmony_ci } 524d5ac70f0Sopenharmony_ci if (dshare->state == SND_PCM_STATE_RUNNING || 525d5ac70f0Sopenharmony_ci dshare->state == SND_PCM_STATE_DRAINING) { 526d5ac70f0Sopenharmony_ci /* ok, we commit the changes after the validation of area */ 527d5ac70f0Sopenharmony_ci /* it's intended, although the result might be crappy */ 528d5ac70f0Sopenharmony_ci snd_pcm_dshare_sync_area(pcm); 529d5ac70f0Sopenharmony_ci /* clear timer queue to avoid a bogus return from poll */ 530d5ac70f0Sopenharmony_ci if (snd_pcm_mmap_playback_avail(pcm) < pcm->avail_min) 531d5ac70f0Sopenharmony_ci snd_pcm_direct_clear_timer_queue(dshare); 532d5ac70f0Sopenharmony_ci } 533d5ac70f0Sopenharmony_ci return size; 534d5ac70f0Sopenharmony_ci} 535d5ac70f0Sopenharmony_ci 536d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dshare_avail_update(snd_pcm_t *pcm) 537d5ac70f0Sopenharmony_ci{ 538d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 539d5ac70f0Sopenharmony_ci int err; 540d5ac70f0Sopenharmony_ci 541d5ac70f0Sopenharmony_ci if (dshare->state == SND_PCM_STATE_RUNNING || 542d5ac70f0Sopenharmony_ci dshare->state == SND_PCM_STATE_DRAINING) { 543d5ac70f0Sopenharmony_ci if ((err = snd_pcm_dshare_sync_ptr(pcm)) < 0) 544d5ac70f0Sopenharmony_ci return err; 545d5ac70f0Sopenharmony_ci } 546d5ac70f0Sopenharmony_ci if (dshare->state == SND_PCM_STATE_XRUN) 547d5ac70f0Sopenharmony_ci return -EPIPE; 548d5ac70f0Sopenharmony_ci 549d5ac70f0Sopenharmony_ci return snd_pcm_mmap_playback_avail(pcm); 550d5ac70f0Sopenharmony_ci} 551d5ac70f0Sopenharmony_ci 552d5ac70f0Sopenharmony_cistatic int snd_pcm_dshare_htimestamp(snd_pcm_t *pcm, 553d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *avail, 554d5ac70f0Sopenharmony_ci snd_htimestamp_t *tstamp) 555d5ac70f0Sopenharmony_ci{ 556d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 557d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail1; 558d5ac70f0Sopenharmony_ci int ok = 0; 559d5ac70f0Sopenharmony_ci 560d5ac70f0Sopenharmony_ci while (1) { 561d5ac70f0Sopenharmony_ci if (dshare->state == SND_PCM_STATE_RUNNING || 562d5ac70f0Sopenharmony_ci dshare->state == SND_PCM_STATE_DRAINING) 563d5ac70f0Sopenharmony_ci snd_pcm_dshare_sync_ptr(pcm); 564d5ac70f0Sopenharmony_ci avail1 = snd_pcm_mmap_playback_avail(pcm); 565d5ac70f0Sopenharmony_ci if (ok && *avail == avail1) 566d5ac70f0Sopenharmony_ci break; 567d5ac70f0Sopenharmony_ci *avail = avail1; 568d5ac70f0Sopenharmony_ci *tstamp = snd_pcm_hw_fast_tstamp(dshare->spcm); 569d5ac70f0Sopenharmony_ci ok = 1; 570d5ac70f0Sopenharmony_ci } 571d5ac70f0Sopenharmony_ci return 0; 572d5ac70f0Sopenharmony_ci} 573d5ac70f0Sopenharmony_ci 574d5ac70f0Sopenharmony_cistatic void snd_pcm_dshare_dump(snd_pcm_t *pcm, snd_output_t *out) 575d5ac70f0Sopenharmony_ci{ 576d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare = pcm->private_data; 577d5ac70f0Sopenharmony_ci 578d5ac70f0Sopenharmony_ci snd_output_printf(out, "Direct Share PCM\n"); 579d5ac70f0Sopenharmony_ci if (pcm->setup) { 580d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 581d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 582d5ac70f0Sopenharmony_ci } 583d5ac70f0Sopenharmony_ci if (dshare->spcm) 584d5ac70f0Sopenharmony_ci snd_pcm_dump(dshare->spcm, out); 585d5ac70f0Sopenharmony_ci} 586d5ac70f0Sopenharmony_ci 587d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_dshare_dummy_ops = { 588d5ac70f0Sopenharmony_ci .close = snd_pcm_dshare_close, 589d5ac70f0Sopenharmony_ci}; 590d5ac70f0Sopenharmony_ci 591d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_dshare_fast_dummy_ops; 592d5ac70f0Sopenharmony_ci 593d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_dshare_ops = { 594d5ac70f0Sopenharmony_ci .close = snd_pcm_dshare_close, 595d5ac70f0Sopenharmony_ci .info = snd_pcm_direct_info, 596d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_direct_hw_refine, 597d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_direct_hw_params, 598d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_direct_hw_free, 599d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_direct_sw_params, 600d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_direct_channel_info, 601d5ac70f0Sopenharmony_ci .dump = snd_pcm_dshare_dump, 602d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_direct_nonblock, 603d5ac70f0Sopenharmony_ci .async = snd_pcm_direct_async, 604d5ac70f0Sopenharmony_ci .mmap = snd_pcm_direct_mmap, 605d5ac70f0Sopenharmony_ci .munmap = snd_pcm_direct_munmap, 606d5ac70f0Sopenharmony_ci .get_chmap = snd_pcm_direct_get_chmap, 607d5ac70f0Sopenharmony_ci .set_chmap = snd_pcm_direct_set_chmap, 608d5ac70f0Sopenharmony_ci}; 609d5ac70f0Sopenharmony_ci 610d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = { 611d5ac70f0Sopenharmony_ci .status = snd_pcm_dshare_status, 612d5ac70f0Sopenharmony_ci .state = snd_pcm_dshare_state, 613d5ac70f0Sopenharmony_ci .hwsync = snd_pcm_dshare_hwsync, 614d5ac70f0Sopenharmony_ci .delay = snd_pcm_dshare_delay, 615d5ac70f0Sopenharmony_ci .prepare = snd_pcm_direct_prepare, 616d5ac70f0Sopenharmony_ci .reset = snd_pcm_dshare_reset, 617d5ac70f0Sopenharmony_ci .start = snd_pcm_dshare_start, 618d5ac70f0Sopenharmony_ci .drop = snd_pcm_dshare_drop, 619d5ac70f0Sopenharmony_ci .drain = snd_pcm_dshare_drain, 620d5ac70f0Sopenharmony_ci .pause = snd_pcm_dshare_pause, 621d5ac70f0Sopenharmony_ci .rewindable = snd_pcm_dshare_rewindable, 622d5ac70f0Sopenharmony_ci .rewind = snd_pcm_dshare_rewind, 623d5ac70f0Sopenharmony_ci .forwardable = snd_pcm_dshare_forwardable, 624d5ac70f0Sopenharmony_ci .forward = snd_pcm_dshare_forward, 625d5ac70f0Sopenharmony_ci .resume = snd_pcm_direct_resume, 626d5ac70f0Sopenharmony_ci .link = NULL, 627d5ac70f0Sopenharmony_ci .link_slaves = NULL, 628d5ac70f0Sopenharmony_ci .unlink = NULL, 629d5ac70f0Sopenharmony_ci .writei = snd_pcm_mmap_writei, 630d5ac70f0Sopenharmony_ci .writen = snd_pcm_mmap_writen, 631d5ac70f0Sopenharmony_ci .readi = snd_pcm_dshare_readi, 632d5ac70f0Sopenharmony_ci .readn = snd_pcm_dshare_readn, 633d5ac70f0Sopenharmony_ci .avail_update = snd_pcm_dshare_avail_update, 634d5ac70f0Sopenharmony_ci .mmap_commit = snd_pcm_dshare_mmap_commit, 635d5ac70f0Sopenharmony_ci .htimestamp = snd_pcm_dshare_htimestamp, 636d5ac70f0Sopenharmony_ci .poll_descriptors = snd_pcm_direct_poll_descriptors, 637d5ac70f0Sopenharmony_ci .poll_descriptors_count = NULL, 638d5ac70f0Sopenharmony_ci .poll_revents = snd_pcm_direct_poll_revents, 639d5ac70f0Sopenharmony_ci}; 640d5ac70f0Sopenharmony_ci 641d5ac70f0Sopenharmony_ci/** 642d5ac70f0Sopenharmony_ci * \brief Creates a new dshare PCM 643d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 644d5ac70f0Sopenharmony_ci * \param name Name of PCM 645d5ac70f0Sopenharmony_ci * \param opts Direct PCM configurations 646d5ac70f0Sopenharmony_ci * \param params Parameters for slave 647d5ac70f0Sopenharmony_ci * \param root Configuration root 648d5ac70f0Sopenharmony_ci * \param sconf Slave configuration 649d5ac70f0Sopenharmony_ci * \param stream PCM Direction (stream) 650d5ac70f0Sopenharmony_ci * \param mode PCM Mode 651d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 652d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 653d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 654d5ac70f0Sopenharmony_ci * changed in future. 655d5ac70f0Sopenharmony_ci */ 656d5ac70f0Sopenharmony_ciint snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, 657d5ac70f0Sopenharmony_ci struct snd_pcm_direct_open_conf *opts, 658d5ac70f0Sopenharmony_ci struct slave_params *params, 659d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *sconf, 660d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 661d5ac70f0Sopenharmony_ci{ 662d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, *spcm = NULL; 663d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dshare; 664d5ac70f0Sopenharmony_ci int ret, first_instance; 665d5ac70f0Sopenharmony_ci unsigned int chn; 666d5ac70f0Sopenharmony_ci 667d5ac70f0Sopenharmony_ci assert(pcmp); 668d5ac70f0Sopenharmony_ci 669d5ac70f0Sopenharmony_ci if (stream != SND_PCM_STREAM_PLAYBACK) { 670d5ac70f0Sopenharmony_ci SNDERR("The dshare plugin supports only playback stream"); 671d5ac70f0Sopenharmony_ci return -EINVAL; 672d5ac70f0Sopenharmony_ci } 673d5ac70f0Sopenharmony_ci 674d5ac70f0Sopenharmony_ci ret = _snd_pcm_direct_new(&pcm, &dshare, SND_PCM_TYPE_DSHARE, name, opts, params, stream, mode); 675d5ac70f0Sopenharmony_ci if (ret < 0) 676d5ac70f0Sopenharmony_ci return ret; 677d5ac70f0Sopenharmony_ci first_instance = ret; 678d5ac70f0Sopenharmony_ci 679d5ac70f0Sopenharmony_ci if (!dshare->bindings) { 680d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_dshare_dummy_ops; 681d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_dshare_fast_dummy_ops; 682d5ac70f0Sopenharmony_ci } else { 683d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_dshare_ops; 684d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_dshare_fast_ops; 685d5ac70f0Sopenharmony_ci } 686d5ac70f0Sopenharmony_ci pcm->private_data = dshare; 687d5ac70f0Sopenharmony_ci dshare->state = SND_PCM_STATE_OPEN; 688d5ac70f0Sopenharmony_ci dshare->slowptr = opts->slowptr; 689d5ac70f0Sopenharmony_ci dshare->max_periods = opts->max_periods; 690d5ac70f0Sopenharmony_ci dshare->var_periodsize = opts->var_periodsize; 691d5ac70f0Sopenharmony_ci dshare->hw_ptr_alignment = opts->hw_ptr_alignment; 692d5ac70f0Sopenharmony_ci dshare->sync_ptr = snd_pcm_dshare_sync_ptr; 693d5ac70f0Sopenharmony_ci 694d5ac70f0Sopenharmony_ci retry: 695d5ac70f0Sopenharmony_ci if (first_instance) { 696d5ac70f0Sopenharmony_ci /* recursion is already checked in 697d5ac70f0Sopenharmony_ci snd_pcm_direct_get_slave_ipc_offset() */ 698d5ac70f0Sopenharmony_ci ret = snd_pcm_open_slave(&spcm, root, sconf, stream, 699d5ac70f0Sopenharmony_ci mode | SND_PCM_NONBLOCK, NULL); 700d5ac70f0Sopenharmony_ci if (ret < 0) { 701d5ac70f0Sopenharmony_ci SNDERR("unable to open slave"); 702d5ac70f0Sopenharmony_ci goto _err; 703d5ac70f0Sopenharmony_ci } 704d5ac70f0Sopenharmony_ci 705d5ac70f0Sopenharmony_ci if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { 706d5ac70f0Sopenharmony_ci SNDERR("dshare plugin can be only connected to hw plugin"); 707d5ac70f0Sopenharmony_ci goto _err; 708d5ac70f0Sopenharmony_ci } 709d5ac70f0Sopenharmony_ci 710d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_initialize_slave(dshare, spcm, params); 711d5ac70f0Sopenharmony_ci if (ret < 0) { 712d5ac70f0Sopenharmony_ci SNDERR("unable to initialize slave"); 713d5ac70f0Sopenharmony_ci goto _err; 714d5ac70f0Sopenharmony_ci } 715d5ac70f0Sopenharmony_ci 716d5ac70f0Sopenharmony_ci dshare->spcm = spcm; 717d5ac70f0Sopenharmony_ci 718d5ac70f0Sopenharmony_ci if (dshare->shmptr->use_server) { 719d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_server_create(dshare); 720d5ac70f0Sopenharmony_ci if (ret < 0) { 721d5ac70f0Sopenharmony_ci SNDERR("unable to create server"); 722d5ac70f0Sopenharmony_ci goto _err; 723d5ac70f0Sopenharmony_ci } 724d5ac70f0Sopenharmony_ci } 725d5ac70f0Sopenharmony_ci 726d5ac70f0Sopenharmony_ci dshare->shmptr->type = spcm->type; 727d5ac70f0Sopenharmony_ci } else { 728d5ac70f0Sopenharmony_ci if (dshare->shmptr->use_server) { 729d5ac70f0Sopenharmony_ci /* up semaphore to avoid deadlock */ 730d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); 731d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_client_connect(dshare); 732d5ac70f0Sopenharmony_ci if (ret < 0) { 733d5ac70f0Sopenharmony_ci SNDERR("unable to connect client"); 734d5ac70f0Sopenharmony_ci goto _err_nosem; 735d5ac70f0Sopenharmony_ci } 736d5ac70f0Sopenharmony_ci 737d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT); 738d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_open_secondary_client(&spcm, dshare, "dshare_client"); 739d5ac70f0Sopenharmony_ci if (ret < 0) 740d5ac70f0Sopenharmony_ci goto _err; 741d5ac70f0Sopenharmony_ci 742d5ac70f0Sopenharmony_ci } else { 743d5ac70f0Sopenharmony_ci 744d5ac70f0Sopenharmony_ci ret = snd_pcm_open_slave(&spcm, root, sconf, stream, 745d5ac70f0Sopenharmony_ci mode | SND_PCM_NONBLOCK | 746d5ac70f0Sopenharmony_ci SND_PCM_APPEND, 747d5ac70f0Sopenharmony_ci NULL); 748d5ac70f0Sopenharmony_ci if (ret < 0) { 749d5ac70f0Sopenharmony_ci /* all other streams have been closed; 750d5ac70f0Sopenharmony_ci * retry as the first instance 751d5ac70f0Sopenharmony_ci */ 752d5ac70f0Sopenharmony_ci if (ret == -EBADFD) { 753d5ac70f0Sopenharmony_ci first_instance = 1; 754d5ac70f0Sopenharmony_ci goto retry; 755d5ac70f0Sopenharmony_ci } 756d5ac70f0Sopenharmony_ci SNDERR("unable to open slave"); 757d5ac70f0Sopenharmony_ci goto _err; 758d5ac70f0Sopenharmony_ci } 759d5ac70f0Sopenharmony_ci if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { 760d5ac70f0Sopenharmony_ci SNDERR("dshare plugin can be only connected to hw plugin"); 761d5ac70f0Sopenharmony_ci ret = -EINVAL; 762d5ac70f0Sopenharmony_ci goto _err; 763d5ac70f0Sopenharmony_ci } 764d5ac70f0Sopenharmony_ci 765d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_initialize_secondary_slave(dshare, spcm, params); 766d5ac70f0Sopenharmony_ci if (ret < 0) { 767d5ac70f0Sopenharmony_ci SNDERR("unable to initialize slave"); 768d5ac70f0Sopenharmony_ci goto _err; 769d5ac70f0Sopenharmony_ci } 770d5ac70f0Sopenharmony_ci } 771d5ac70f0Sopenharmony_ci 772d5ac70f0Sopenharmony_ci dshare->spcm = spcm; 773d5ac70f0Sopenharmony_ci } 774d5ac70f0Sopenharmony_ci 775d5ac70f0Sopenharmony_ci for (chn = 0; dshare->bindings && (chn < dshare->channels); chn++) { 776d5ac70f0Sopenharmony_ci unsigned int dchn = dshare->bindings ? dshare->bindings[chn] : chn; 777d5ac70f0Sopenharmony_ci if (dchn != UINT_MAX) 778d5ac70f0Sopenharmony_ci dshare->u.dshare.chn_mask |= (1ULL << dchn); 779d5ac70f0Sopenharmony_ci } 780d5ac70f0Sopenharmony_ci if (dshare->shmptr->u.dshare.chn_mask & dshare->u.dshare.chn_mask) { 781d5ac70f0Sopenharmony_ci SNDERR("destination channel specified in bindings is already used"); 782d5ac70f0Sopenharmony_ci dshare->u.dshare.chn_mask = 0; 783d5ac70f0Sopenharmony_ci ret = -EINVAL; 784d5ac70f0Sopenharmony_ci goto _err; 785d5ac70f0Sopenharmony_ci } 786d5ac70f0Sopenharmony_ci dshare->shmptr->u.dshare.chn_mask |= dshare->u.dshare.chn_mask; 787d5ac70f0Sopenharmony_ci 788d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_initialize_poll_fd(dshare); 789d5ac70f0Sopenharmony_ci if (ret < 0) { 790d5ac70f0Sopenharmony_ci SNDERR("unable to initialize poll_fd"); 791d5ac70f0Sopenharmony_ci goto _err; 792d5ac70f0Sopenharmony_ci } 793d5ac70f0Sopenharmony_ci 794d5ac70f0Sopenharmony_ci pcm->poll_fd = dshare->poll_fd; 795d5ac70f0Sopenharmony_ci pcm->poll_events = POLLIN; /* it's different than other plugins */ 796d5ac70f0Sopenharmony_ci pcm->tstamp_type = spcm->tstamp_type; 797d5ac70f0Sopenharmony_ci pcm->mmap_rw = 1; 798d5ac70f0Sopenharmony_ci snd_pcm_set_hw_ptr(pcm, &dshare->hw_ptr, -1, 0); 799d5ac70f0Sopenharmony_ci snd_pcm_set_appl_ptr(pcm, &dshare->appl_ptr, -1, 0); 800d5ac70f0Sopenharmony_ci 801d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); 802d5ac70f0Sopenharmony_ci 803d5ac70f0Sopenharmony_ci *pcmp = pcm; 804d5ac70f0Sopenharmony_ci return 0; 805d5ac70f0Sopenharmony_ci 806d5ac70f0Sopenharmony_ci _err: 807d5ac70f0Sopenharmony_ci if (dshare->shmptr != (void *) -1) 808d5ac70f0Sopenharmony_ci dshare->shmptr->u.dshare.chn_mask &= ~dshare->u.dshare.chn_mask; 809d5ac70f0Sopenharmony_ci if (dshare->timer) 810d5ac70f0Sopenharmony_ci snd_timer_close(dshare->timer); 811d5ac70f0Sopenharmony_ci if (dshare->server) 812d5ac70f0Sopenharmony_ci snd_pcm_direct_server_discard(dshare); 813d5ac70f0Sopenharmony_ci if (dshare->client) 814d5ac70f0Sopenharmony_ci snd_pcm_direct_client_discard(dshare); 815d5ac70f0Sopenharmony_ci if (spcm) 816d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 817d5ac70f0Sopenharmony_ci if ((dshare->shmid >= 0) && (snd_pcm_direct_shm_discard(dshare))) { 818d5ac70f0Sopenharmony_ci if (snd_pcm_direct_semaphore_discard(dshare)) 819d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_final(dshare, DIRECT_IPC_SEM_CLIENT); 820d5ac70f0Sopenharmony_ci } else 821d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); 822d5ac70f0Sopenharmony_ci _err_nosem: 823d5ac70f0Sopenharmony_ci free(dshare->bindings); 824d5ac70f0Sopenharmony_ci free(dshare); 825d5ac70f0Sopenharmony_ci snd_pcm_free(pcm); 826d5ac70f0Sopenharmony_ci return ret; 827d5ac70f0Sopenharmony_ci} 828d5ac70f0Sopenharmony_ci 829d5ac70f0Sopenharmony_ci/*! \page pcm_plugins 830d5ac70f0Sopenharmony_ci 831d5ac70f0Sopenharmony_ci\section pcm_plugins_dshare Plugin: dshare 832d5ac70f0Sopenharmony_ci 833d5ac70f0Sopenharmony_ciThis plugin provides sharing channels. 834d5ac70f0Sopenharmony_ciUnlike \ref pcm_plugins_share "share plugin", this plugin doesn't need 835d5ac70f0Sopenharmony_cithe explicit server program but accesses the shared buffer concurrently 836d5ac70f0Sopenharmony_cifrom each client as well as \ref pcm_plugins_dmix "dmix" and 837d5ac70f0Sopenharmony_ci\ref pcm_plugins_dsnoop "dsnoop" plugins do. 838d5ac70f0Sopenharmony_ciThe parameters below are almost identical with these plugins. 839d5ac70f0Sopenharmony_ci 840d5ac70f0Sopenharmony_ci\code 841d5ac70f0Sopenharmony_cipcm.name { 842d5ac70f0Sopenharmony_ci type dshare # Direct sharing 843d5ac70f0Sopenharmony_ci ipc_key INT # unique IPC key 844d5ac70f0Sopenharmony_ci ipc_key_add_uid BOOL # add current uid to unique IPC key 845d5ac70f0Sopenharmony_ci ipc_perm INT # IPC permissions (octal, default 0600) 846d5ac70f0Sopenharmony_ci hw_ptr_alignment STR # Slave application and hw pointer alignment type 847d5ac70f0Sopenharmony_ci # STR can be one of the below strings : 848d5ac70f0Sopenharmony_ci # no (or off) 849d5ac70f0Sopenharmony_ci # roundup 850d5ac70f0Sopenharmony_ci # rounddown 851d5ac70f0Sopenharmony_ci # auto (default) 852d5ac70f0Sopenharmony_ci tstamp_type STR # timestamp type 853d5ac70f0Sopenharmony_ci # STR can be one of the below strings : 854d5ac70f0Sopenharmony_ci # default, gettimeofday, monotonic, monotonic_raw 855d5ac70f0Sopenharmony_ci slave STR 856d5ac70f0Sopenharmony_ci # or 857d5ac70f0Sopenharmony_ci slave { # Slave definition 858d5ac70f0Sopenharmony_ci pcm STR # slave PCM name 859d5ac70f0Sopenharmony_ci # or 860d5ac70f0Sopenharmony_ci pcm { } # slave PCM definition 861d5ac70f0Sopenharmony_ci format STR # format definition 862d5ac70f0Sopenharmony_ci rate INT # rate definition 863d5ac70f0Sopenharmony_ci channels INT 864d5ac70f0Sopenharmony_ci period_time INT # in usec 865d5ac70f0Sopenharmony_ci # or 866d5ac70f0Sopenharmony_ci period_size INT # in frames 867d5ac70f0Sopenharmony_ci buffer_time INT # in usec 868d5ac70f0Sopenharmony_ci # or 869d5ac70f0Sopenharmony_ci buffer_size INT # in frames 870d5ac70f0Sopenharmony_ci periods INT # when buffer_size or buffer_time is not specified 871d5ac70f0Sopenharmony_ci } 872d5ac70f0Sopenharmony_ci bindings { # note: this is client independent!!! 873d5ac70f0Sopenharmony_ci N INT # maps slave channel to client channel N 874d5ac70f0Sopenharmony_ci } 875d5ac70f0Sopenharmony_ci slowptr BOOL # slow but more precise pointer updates 876d5ac70f0Sopenharmony_ci} 877d5ac70f0Sopenharmony_ci\endcode 878d5ac70f0Sopenharmony_ci 879d5ac70f0Sopenharmony_ci<code>hw_ptr_alignment</code> specifies slave application and hw 880d5ac70f0Sopenharmony_cipointer alignment type. By default hw_ptr_alignment is auto. Below are 881d5ac70f0Sopenharmony_cithe possible configurations: 882d5ac70f0Sopenharmony_ci- no: minimal latency with minimal frames dropped at startup. But 883d5ac70f0Sopenharmony_ci wakeup of application (return from snd_pcm_wait() or poll()) can 884d5ac70f0Sopenharmony_ci take up to 2 * period. 885d5ac70f0Sopenharmony_ci- roundup: It is guaranteed that all frames will be played at 886d5ac70f0Sopenharmony_ci startup. But the latency will increase upto period-1 frames. 887d5ac70f0Sopenharmony_ci- rounddown: It is guaranteed that a wakeup will happen for each 888d5ac70f0Sopenharmony_ci period and frames can be written from application. But on startup 889d5ac70f0Sopenharmony_ci upto period-1 frames will be dropped. 890d5ac70f0Sopenharmony_ci- auto: Selects the best approach depending on the used period and 891d5ac70f0Sopenharmony_ci buffer size. 892d5ac70f0Sopenharmony_ci If the application buffer size is < 2 * application period, 893d5ac70f0Sopenharmony_ci "roundup" will be selected to avoid under runs. If the slave_period 894d5ac70f0Sopenharmony_ci is < 10ms we could expect that there are low latency 895d5ac70f0Sopenharmony_ci requirements. Therefore "rounddown" will be chosen to avoid long 896d5ac70f0Sopenharmony_ci wakeup times. Such wakeup delay could otherwise end up with Xruns in 897d5ac70f0Sopenharmony_ci case of a dependency to another sound device (e.g. forwarding of 898d5ac70f0Sopenharmony_ci microphone to speaker). Else "no" will be chosen. 899d5ac70f0Sopenharmony_ci 900d5ac70f0Sopenharmony_ci\subsection pcm_plugins_dshare_funcref Function reference 901d5ac70f0Sopenharmony_ci 902d5ac70f0Sopenharmony_ci<UL> 903d5ac70f0Sopenharmony_ci <LI>snd_pcm_dshare_open() 904d5ac70f0Sopenharmony_ci <LI>_snd_pcm_dshare_open() 905d5ac70f0Sopenharmony_ci</UL> 906d5ac70f0Sopenharmony_ci 907d5ac70f0Sopenharmony_ci*/ 908d5ac70f0Sopenharmony_ci 909d5ac70f0Sopenharmony_ci/** 910d5ac70f0Sopenharmony_ci * \brief Creates a new dshare PCM 911d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 912d5ac70f0Sopenharmony_ci * \param name Name of PCM 913d5ac70f0Sopenharmony_ci * \param root Root configuration node 914d5ac70f0Sopenharmony_ci * \param conf Configuration node with dshare PCM description 915d5ac70f0Sopenharmony_ci * \param stream PCM Stream 916d5ac70f0Sopenharmony_ci * \param mode PCM Mode 917d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 918d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 919d5ac70f0Sopenharmony_ci * changed in future. 920d5ac70f0Sopenharmony_ci */ 921d5ac70f0Sopenharmony_ciint _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, 922d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *conf, 923d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 924d5ac70f0Sopenharmony_ci{ 925d5ac70f0Sopenharmony_ci snd_config_t *sconf; 926d5ac70f0Sopenharmony_ci struct slave_params params; 927d5ac70f0Sopenharmony_ci struct snd_pcm_direct_open_conf dopen; 928d5ac70f0Sopenharmony_ci int bsize, psize; 929d5ac70f0Sopenharmony_ci int err; 930d5ac70f0Sopenharmony_ci 931d5ac70f0Sopenharmony_ci err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen); 932d5ac70f0Sopenharmony_ci if (err < 0) 933d5ac70f0Sopenharmony_ci return err; 934d5ac70f0Sopenharmony_ci 935d5ac70f0Sopenharmony_ci /* the default settings, it might be invalid for some hardware */ 936d5ac70f0Sopenharmony_ci params.format = SND_PCM_FORMAT_S16; 937d5ac70f0Sopenharmony_ci params.rate = 48000; 938d5ac70f0Sopenharmony_ci params.channels = 2; 939d5ac70f0Sopenharmony_ci params.period_time = -1; 940d5ac70f0Sopenharmony_ci params.buffer_time = -1; 941d5ac70f0Sopenharmony_ci bsize = psize = -1; 942d5ac70f0Sopenharmony_ci params.periods = 3; 943d5ac70f0Sopenharmony_ci err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8, 944d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format, 945d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate, 946d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels, 947d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time, 948d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time, 949d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize, 950d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize, 951d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods); 952d5ac70f0Sopenharmony_ci if (err < 0) 953d5ac70f0Sopenharmony_ci return err; 954d5ac70f0Sopenharmony_ci 955d5ac70f0Sopenharmony_ci /* set a reasonable default */ 956d5ac70f0Sopenharmony_ci if (psize == -1 && params.period_time == -1) 957d5ac70f0Sopenharmony_ci params.period_time = 125000; /* 0.125 seconds */ 958d5ac70f0Sopenharmony_ci 959d5ac70f0Sopenharmony_ci if (params.format == -2) 960d5ac70f0Sopenharmony_ci params.format = SND_PCM_FORMAT_UNKNOWN; 961d5ac70f0Sopenharmony_ci 962d5ac70f0Sopenharmony_ci params.period_size = psize; 963d5ac70f0Sopenharmony_ci params.buffer_size = bsize; 964d5ac70f0Sopenharmony_ci 965d5ac70f0Sopenharmony_ci err = snd_pcm_dshare_open(pcmp, name, &dopen, ¶ms, 966d5ac70f0Sopenharmony_ci root, sconf, stream, mode); 967d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 968d5ac70f0Sopenharmony_ci return err; 969d5ac70f0Sopenharmony_ci} 970d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 971d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_dshare_open, SND_PCM_DLSYM_VERSION); 972d5ac70f0Sopenharmony_ci#endif 973