1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_dsnoop.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM_Plugins 4d5ac70f0Sopenharmony_ci * \brief PCM Capture Stream Snooping (dsnoop) Plugin Interface 5d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 6d5ac70f0Sopenharmony_ci * \date 2003 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * PCM - Capture Stream Snooping 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_dsnoop = ""; 52d5ac70f0Sopenharmony_ci#endif 53d5ac70f0Sopenharmony_ci 54d5ac70f0Sopenharmony_ci/* 55d5ac70f0Sopenharmony_ci * 56d5ac70f0Sopenharmony_ci */ 57d5ac70f0Sopenharmony_ci 58d5ac70f0Sopenharmony_cistatic int snoop_timestamp(snd_pcm_t *pcm) 59d5ac70f0Sopenharmony_ci{ 60d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 61d5ac70f0Sopenharmony_ci snd_pcm_uframes_t ptr1 = -2LL /* invalid value */, ptr2; 62d5ac70f0Sopenharmony_ci 63d5ac70f0Sopenharmony_ci /* loop is required to sync hw.ptr with timestamp */ 64d5ac70f0Sopenharmony_ci while (1) { 65d5ac70f0Sopenharmony_ci ptr2 = *dsnoop->spcm->hw.ptr; 66d5ac70f0Sopenharmony_ci if (ptr1 == ptr2) 67d5ac70f0Sopenharmony_ci break; 68d5ac70f0Sopenharmony_ci ptr1 = ptr2; 69d5ac70f0Sopenharmony_ci dsnoop->update_tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm); 70d5ac70f0Sopenharmony_ci } 71d5ac70f0Sopenharmony_ci dsnoop->slave_hw_ptr = ptr1; 72d5ac70f0Sopenharmony_ci return 0; 73d5ac70f0Sopenharmony_ci} 74d5ac70f0Sopenharmony_ci 75d5ac70f0Sopenharmony_cistatic void snoop_areas(snd_pcm_direct_t *dsnoop, 76d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, 77d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *dst_areas, 78d5ac70f0Sopenharmony_ci snd_pcm_uframes_t src_ofs, 79d5ac70f0Sopenharmony_ci snd_pcm_uframes_t dst_ofs, 80d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 81d5ac70f0Sopenharmony_ci{ 82d5ac70f0Sopenharmony_ci unsigned int chn, schn, channels; 83d5ac70f0Sopenharmony_ci snd_pcm_format_t format; 84d5ac70f0Sopenharmony_ci 85d5ac70f0Sopenharmony_ci channels = dsnoop->channels; 86d5ac70f0Sopenharmony_ci format = dsnoop->shmptr->s.format; 87d5ac70f0Sopenharmony_ci if (dsnoop->interleaved) { 88d5ac70f0Sopenharmony_ci unsigned int fbytes = snd_pcm_format_physical_width(format) / 8; 89d5ac70f0Sopenharmony_ci memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes), 90d5ac70f0Sopenharmony_ci ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes), 91d5ac70f0Sopenharmony_ci size * channels * fbytes); 92d5ac70f0Sopenharmony_ci } else { 93d5ac70f0Sopenharmony_ci for (chn = 0; chn < channels; chn++) { 94d5ac70f0Sopenharmony_ci schn = dsnoop->bindings ? dsnoop->bindings[chn] : chn; 95d5ac70f0Sopenharmony_ci snd_pcm_area_copy(&dst_areas[chn], dst_ofs, &src_areas[schn], src_ofs, size, format); 96d5ac70f0Sopenharmony_ci } 97d5ac70f0Sopenharmony_ci } 98d5ac70f0Sopenharmony_ci} 99d5ac70f0Sopenharmony_ci 100d5ac70f0Sopenharmony_ci/* 101d5ac70f0Sopenharmony_ci * synchronize shm ring buffer with hardware 102d5ac70f0Sopenharmony_ci */ 103d5ac70f0Sopenharmony_cistatic void snd_pcm_dsnoop_sync_area(snd_pcm_t *pcm, snd_pcm_uframes_t slave_hw_ptr, snd_pcm_uframes_t size) 104d5ac70f0Sopenharmony_ci{ 105d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 106d5ac70f0Sopenharmony_ci snd_pcm_uframes_t hw_ptr = dsnoop->hw_ptr; 107d5ac70f0Sopenharmony_ci snd_pcm_uframes_t transfer; 108d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *src_areas, *dst_areas; 109d5ac70f0Sopenharmony_ci 110d5ac70f0Sopenharmony_ci /* add sample areas here */ 111d5ac70f0Sopenharmony_ci dst_areas = snd_pcm_mmap_areas(pcm); 112d5ac70f0Sopenharmony_ci src_areas = snd_pcm_mmap_areas(dsnoop->spcm); 113d5ac70f0Sopenharmony_ci hw_ptr %= pcm->buffer_size; 114d5ac70f0Sopenharmony_ci slave_hw_ptr %= dsnoop->slave_buffer_size; 115d5ac70f0Sopenharmony_ci while (size > 0) { 116d5ac70f0Sopenharmony_ci transfer = hw_ptr + size > pcm->buffer_size ? pcm->buffer_size - hw_ptr : size; 117d5ac70f0Sopenharmony_ci transfer = slave_hw_ptr + transfer > dsnoop->slave_buffer_size ? 118d5ac70f0Sopenharmony_ci dsnoop->slave_buffer_size - slave_hw_ptr : transfer; 119d5ac70f0Sopenharmony_ci size -= transfer; 120d5ac70f0Sopenharmony_ci snoop_areas(dsnoop, src_areas, dst_areas, slave_hw_ptr, hw_ptr, transfer); 121d5ac70f0Sopenharmony_ci slave_hw_ptr += transfer; 122d5ac70f0Sopenharmony_ci slave_hw_ptr %= dsnoop->slave_buffer_size; 123d5ac70f0Sopenharmony_ci hw_ptr += transfer; 124d5ac70f0Sopenharmony_ci hw_ptr %= pcm->buffer_size; 125d5ac70f0Sopenharmony_ci } 126d5ac70f0Sopenharmony_ci} 127d5ac70f0Sopenharmony_ci 128d5ac70f0Sopenharmony_ci/* 129d5ac70f0Sopenharmony_ci * synchronize hardware pointer (hw_ptr) with ours 130d5ac70f0Sopenharmony_ci */ 131d5ac70f0Sopenharmony_cistatic int snd_pcm_dsnoop_sync_ptr(snd_pcm_t *pcm) 132d5ac70f0Sopenharmony_ci{ 133d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 134d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail; 135d5ac70f0Sopenharmony_ci snd_pcm_sframes_t diff; 136d5ac70f0Sopenharmony_ci int err; 137d5ac70f0Sopenharmony_ci 138d5ac70f0Sopenharmony_ci if (dsnoop->slowptr) 139d5ac70f0Sopenharmony_ci snd_pcm_hwsync(dsnoop->spcm); 140d5ac70f0Sopenharmony_ci old_slave_hw_ptr = dsnoop->slave_hw_ptr; 141d5ac70f0Sopenharmony_ci snoop_timestamp(pcm); 142d5ac70f0Sopenharmony_ci slave_hw_ptr = dsnoop->slave_hw_ptr; 143d5ac70f0Sopenharmony_ci err = snd_pcm_direct_check_xrun(dsnoop, pcm); 144d5ac70f0Sopenharmony_ci if (err < 0) 145d5ac70f0Sopenharmony_ci return err; 146d5ac70f0Sopenharmony_ci diff = pcm_frame_diff(slave_hw_ptr, old_slave_hw_ptr, dsnoop->slave_boundary); 147d5ac70f0Sopenharmony_ci if (diff == 0) /* fast path */ 148d5ac70f0Sopenharmony_ci return 0; 149d5ac70f0Sopenharmony_ci snd_pcm_dsnoop_sync_area(pcm, old_slave_hw_ptr, diff); 150d5ac70f0Sopenharmony_ci dsnoop->hw_ptr += diff; 151d5ac70f0Sopenharmony_ci dsnoop->hw_ptr %= pcm->boundary; 152d5ac70f0Sopenharmony_ci // printf("sync ptr diff = %li\n", diff); 153d5ac70f0Sopenharmony_ci if (pcm->stop_threshold >= pcm->boundary) /* don't care */ 154d5ac70f0Sopenharmony_ci return 0; 155d5ac70f0Sopenharmony_ci if ((avail = snd_pcm_mmap_capture_avail(pcm)) >= pcm->stop_threshold) { 156d5ac70f0Sopenharmony_ci gettimestamp(&dsnoop->trigger_tstamp, pcm->tstamp_type); 157d5ac70f0Sopenharmony_ci dsnoop->state = SND_PCM_STATE_XRUN; 158d5ac70f0Sopenharmony_ci dsnoop->avail_max = avail; 159d5ac70f0Sopenharmony_ci return -EPIPE; 160d5ac70f0Sopenharmony_ci } 161d5ac70f0Sopenharmony_ci if (avail > dsnoop->avail_max) 162d5ac70f0Sopenharmony_ci dsnoop->avail_max = avail; 163d5ac70f0Sopenharmony_ci return 0; 164d5ac70f0Sopenharmony_ci} 165d5ac70f0Sopenharmony_ci 166d5ac70f0Sopenharmony_ci/* 167d5ac70f0Sopenharmony_ci * plugin implementation 168d5ac70f0Sopenharmony_ci */ 169d5ac70f0Sopenharmony_ci 170d5ac70f0Sopenharmony_cistatic int snd_pcm_dsnoop_status(snd_pcm_t *pcm, snd_pcm_status_t * status) 171d5ac70f0Sopenharmony_ci{ 172d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 173d5ac70f0Sopenharmony_ci snd_pcm_state_t state; 174d5ac70f0Sopenharmony_ci 175d5ac70f0Sopenharmony_ci switch(dsnoop->state) { 176d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DRAINING: 177d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 178d5ac70f0Sopenharmony_ci snd_pcm_dsnoop_sync_ptr(pcm); 179d5ac70f0Sopenharmony_ci break; 180d5ac70f0Sopenharmony_ci default: 181d5ac70f0Sopenharmony_ci break; 182d5ac70f0Sopenharmony_ci } 183d5ac70f0Sopenharmony_ci memset(status, 0, sizeof(*status)); 184d5ac70f0Sopenharmony_ci snd_pcm_status(dsnoop->spcm, status); 185d5ac70f0Sopenharmony_ci state = snd_pcm_state(dsnoop->spcm); 186d5ac70f0Sopenharmony_ci status->state = state == SND_PCM_STATE_RUNNING ? dsnoop->state : state; 187d5ac70f0Sopenharmony_ci status->hw_ptr = *pcm->hw.ptr; /* boundary may be different */ 188d5ac70f0Sopenharmony_ci status->appl_ptr = *pcm->appl.ptr; /* slave PCM doesn't set appl_ptr */ 189d5ac70f0Sopenharmony_ci status->trigger_tstamp = dsnoop->trigger_tstamp; 190d5ac70f0Sopenharmony_ci status->avail = snd_pcm_mmap_capture_avail(pcm); 191d5ac70f0Sopenharmony_ci status->avail_max = status->avail > dsnoop->avail_max ? status->avail : dsnoop->avail_max; 192d5ac70f0Sopenharmony_ci dsnoop->avail_max = 0; 193d5ac70f0Sopenharmony_ci status->delay = snd_pcm_mmap_capture_delay(pcm); 194d5ac70f0Sopenharmony_ci return 0; 195d5ac70f0Sopenharmony_ci} 196d5ac70f0Sopenharmony_ci 197d5ac70f0Sopenharmony_cistatic snd_pcm_state_t snd_pcm_dsnoop_state(snd_pcm_t *pcm) 198d5ac70f0Sopenharmony_ci{ 199d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 200d5ac70f0Sopenharmony_ci 201d5ac70f0Sopenharmony_ci snd_pcm_direct_check_xrun(dsnoop, pcm); 202d5ac70f0Sopenharmony_ci return dsnoop->state; 203d5ac70f0Sopenharmony_ci} 204d5ac70f0Sopenharmony_ci 205d5ac70f0Sopenharmony_cistatic int snd_pcm_dsnoop_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 206d5ac70f0Sopenharmony_ci{ 207d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 208d5ac70f0Sopenharmony_ci int err; 209d5ac70f0Sopenharmony_ci 210d5ac70f0Sopenharmony_ci switch(dsnoop->state) { 211d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DRAINING: 212d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 213d5ac70f0Sopenharmony_ci err = snd_pcm_dsnoop_sync_ptr(pcm); 214d5ac70f0Sopenharmony_ci if (err < 0) 215d5ac70f0Sopenharmony_ci return err; 216d5ac70f0Sopenharmony_ci /* Fall through */ 217d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_PREPARED: 218d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_SUSPENDED: 219d5ac70f0Sopenharmony_ci *delayp = snd_pcm_mmap_capture_delay(pcm); 220d5ac70f0Sopenharmony_ci return 0; 221d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_XRUN: 222d5ac70f0Sopenharmony_ci return -EPIPE; 223d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DISCONNECTED: 224d5ac70f0Sopenharmony_ci return -ENODEV; 225d5ac70f0Sopenharmony_ci default: 226d5ac70f0Sopenharmony_ci return -EBADFD; 227d5ac70f0Sopenharmony_ci } 228d5ac70f0Sopenharmony_ci} 229d5ac70f0Sopenharmony_ci 230d5ac70f0Sopenharmony_cistatic int snd_pcm_dsnoop_hwsync(snd_pcm_t *pcm) 231d5ac70f0Sopenharmony_ci{ 232d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 233d5ac70f0Sopenharmony_ci 234d5ac70f0Sopenharmony_ci switch(dsnoop->state) { 235d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DRAINING: 236d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_RUNNING: 237d5ac70f0Sopenharmony_ci return snd_pcm_dsnoop_sync_ptr(pcm); 238d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_PREPARED: 239d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_SUSPENDED: 240d5ac70f0Sopenharmony_ci return 0; 241d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_XRUN: 242d5ac70f0Sopenharmony_ci return -EPIPE; 243d5ac70f0Sopenharmony_ci case SNDRV_PCM_STATE_DISCONNECTED: 244d5ac70f0Sopenharmony_ci return -ENODEV; 245d5ac70f0Sopenharmony_ci default: 246d5ac70f0Sopenharmony_ci return -EBADFD; 247d5ac70f0Sopenharmony_ci } 248d5ac70f0Sopenharmony_ci} 249d5ac70f0Sopenharmony_ci 250d5ac70f0Sopenharmony_cistatic int snd_pcm_dsnoop_reset(snd_pcm_t *pcm) 251d5ac70f0Sopenharmony_ci{ 252d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 253d5ac70f0Sopenharmony_ci dsnoop->hw_ptr %= pcm->period_size; 254d5ac70f0Sopenharmony_ci dsnoop->appl_ptr = dsnoop->hw_ptr; 255d5ac70f0Sopenharmony_ci snd_pcm_direct_reset_slave_ptr(pcm, dsnoop, dsnoop->slave_hw_ptr); 256d5ac70f0Sopenharmony_ci return 0; 257d5ac70f0Sopenharmony_ci} 258d5ac70f0Sopenharmony_ci 259d5ac70f0Sopenharmony_cistatic int snd_pcm_dsnoop_start(snd_pcm_t *pcm) 260d5ac70f0Sopenharmony_ci{ 261d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 262d5ac70f0Sopenharmony_ci int err; 263d5ac70f0Sopenharmony_ci 264d5ac70f0Sopenharmony_ci if (dsnoop->state != SND_PCM_STATE_PREPARED) 265d5ac70f0Sopenharmony_ci return -EBADFD; 266d5ac70f0Sopenharmony_ci snd_pcm_hwsync(dsnoop->spcm); 267d5ac70f0Sopenharmony_ci snoop_timestamp(pcm); 268d5ac70f0Sopenharmony_ci snd_pcm_direct_reset_slave_ptr(pcm, dsnoop, dsnoop->slave_hw_ptr); 269d5ac70f0Sopenharmony_ci err = snd_timer_start(dsnoop->timer); 270d5ac70f0Sopenharmony_ci if (err < 0) 271d5ac70f0Sopenharmony_ci return err; 272d5ac70f0Sopenharmony_ci dsnoop->state = SND_PCM_STATE_RUNNING; 273d5ac70f0Sopenharmony_ci dsnoop->trigger_tstamp = dsnoop->update_tstamp; 274d5ac70f0Sopenharmony_ci return 0; 275d5ac70f0Sopenharmony_ci} 276d5ac70f0Sopenharmony_ci 277d5ac70f0Sopenharmony_cistatic int snd_pcm_dsnoop_drop(snd_pcm_t *pcm) 278d5ac70f0Sopenharmony_ci{ 279d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 280d5ac70f0Sopenharmony_ci if (dsnoop->state == SND_PCM_STATE_OPEN) 281d5ac70f0Sopenharmony_ci return -EBADFD; 282d5ac70f0Sopenharmony_ci dsnoop->state = SND_PCM_STATE_SETUP; 283d5ac70f0Sopenharmony_ci snd_timer_stop(dsnoop->timer); 284d5ac70f0Sopenharmony_ci return 0; 285d5ac70f0Sopenharmony_ci} 286d5ac70f0Sopenharmony_ci 287d5ac70f0Sopenharmony_ci/* locked version */ 288d5ac70f0Sopenharmony_cistatic int __snd_pcm_dsnoop_drain(snd_pcm_t *pcm) 289d5ac70f0Sopenharmony_ci{ 290d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 291d5ac70f0Sopenharmony_ci snd_pcm_uframes_t stop_threshold; 292d5ac70f0Sopenharmony_ci int err; 293d5ac70f0Sopenharmony_ci 294d5ac70f0Sopenharmony_ci if (dsnoop->state == SND_PCM_STATE_OPEN) 295d5ac70f0Sopenharmony_ci return -EBADFD; 296d5ac70f0Sopenharmony_ci stop_threshold = pcm->stop_threshold; 297d5ac70f0Sopenharmony_ci if (pcm->stop_threshold > pcm->buffer_size) 298d5ac70f0Sopenharmony_ci pcm->stop_threshold = pcm->buffer_size; 299d5ac70f0Sopenharmony_ci while (dsnoop->state == SND_PCM_STATE_RUNNING) { 300d5ac70f0Sopenharmony_ci err = snd_pcm_dsnoop_sync_ptr(pcm); 301d5ac70f0Sopenharmony_ci if (err < 0) 302d5ac70f0Sopenharmony_ci break; 303d5ac70f0Sopenharmony_ci if (pcm->mode & SND_PCM_NONBLOCK) 304d5ac70f0Sopenharmony_ci return -EAGAIN; 305d5ac70f0Sopenharmony_ci __snd_pcm_wait_in_lock(pcm, SND_PCM_WAIT_DRAIN); 306d5ac70f0Sopenharmony_ci } 307d5ac70f0Sopenharmony_ci pcm->stop_threshold = stop_threshold; 308d5ac70f0Sopenharmony_ci return snd_pcm_dsnoop_drop(pcm); 309d5ac70f0Sopenharmony_ci} 310d5ac70f0Sopenharmony_ci 311d5ac70f0Sopenharmony_cistatic int snd_pcm_dsnoop_drain(snd_pcm_t *pcm) 312d5ac70f0Sopenharmony_ci{ 313d5ac70f0Sopenharmony_ci int err; 314d5ac70f0Sopenharmony_ci 315d5ac70f0Sopenharmony_ci snd_pcm_lock(pcm); 316d5ac70f0Sopenharmony_ci err = __snd_pcm_dsnoop_drain(pcm); 317d5ac70f0Sopenharmony_ci snd_pcm_unlock(pcm); 318d5ac70f0Sopenharmony_ci return err; 319d5ac70f0Sopenharmony_ci} 320d5ac70f0Sopenharmony_ci 321d5ac70f0Sopenharmony_cistatic int snd_pcm_dsnoop_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED) 322d5ac70f0Sopenharmony_ci{ 323d5ac70f0Sopenharmony_ci return -EIO; 324d5ac70f0Sopenharmony_ci} 325d5ac70f0Sopenharmony_ci 326d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dsnoop_rewindable(snd_pcm_t *pcm) 327d5ac70f0Sopenharmony_ci{ 328d5ac70f0Sopenharmony_ci return snd_pcm_mmap_capture_hw_rewindable(pcm); 329d5ac70f0Sopenharmony_ci} 330d5ac70f0Sopenharmony_ci 331d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dsnoop_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 332d5ac70f0Sopenharmony_ci{ 333d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail; 334d5ac70f0Sopenharmony_ci 335d5ac70f0Sopenharmony_ci avail = snd_pcm_dsnoop_rewindable(pcm); 336d5ac70f0Sopenharmony_ci if (frames > (snd_pcm_uframes_t)avail) 337d5ac70f0Sopenharmony_ci frames = avail; 338d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_backward(pcm, frames); 339d5ac70f0Sopenharmony_ci return frames; 340d5ac70f0Sopenharmony_ci} 341d5ac70f0Sopenharmony_ci 342d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dsnoop_forwardable(snd_pcm_t *pcm) 343d5ac70f0Sopenharmony_ci{ 344d5ac70f0Sopenharmony_ci return snd_pcm_mmap_capture_avail(pcm); 345d5ac70f0Sopenharmony_ci} 346d5ac70f0Sopenharmony_ci 347d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dsnoop_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 348d5ac70f0Sopenharmony_ci{ 349d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail; 350d5ac70f0Sopenharmony_ci 351d5ac70f0Sopenharmony_ci avail = snd_pcm_dsnoop_forwardable(pcm); 352d5ac70f0Sopenharmony_ci if (frames > (snd_pcm_uframes_t)avail) 353d5ac70f0Sopenharmony_ci frames = avail; 354d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, frames); 355d5ac70f0Sopenharmony_ci return frames; 356d5ac70f0Sopenharmony_ci} 357d5ac70f0Sopenharmony_ci 358d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dsnoop_writei(snd_pcm_t *pcm ATTRIBUTE_UNUSED, const void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) 359d5ac70f0Sopenharmony_ci{ 360d5ac70f0Sopenharmony_ci return -ENODEV; 361d5ac70f0Sopenharmony_ci} 362d5ac70f0Sopenharmony_ci 363d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dsnoop_writen(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void **bufs ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED) 364d5ac70f0Sopenharmony_ci{ 365d5ac70f0Sopenharmony_ci return -ENODEV; 366d5ac70f0Sopenharmony_ci} 367d5ac70f0Sopenharmony_ci 368d5ac70f0Sopenharmony_cistatic int snd_pcm_dsnoop_close(snd_pcm_t *pcm) 369d5ac70f0Sopenharmony_ci{ 370d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 371d5ac70f0Sopenharmony_ci 372d5ac70f0Sopenharmony_ci if (dsnoop->timer) 373d5ac70f0Sopenharmony_ci snd_timer_close(dsnoop->timer); 374d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT); 375d5ac70f0Sopenharmony_ci snd_pcm_close(dsnoop->spcm); 376d5ac70f0Sopenharmony_ci if (dsnoop->server) 377d5ac70f0Sopenharmony_ci snd_pcm_direct_server_discard(dsnoop); 378d5ac70f0Sopenharmony_ci if (dsnoop->client) 379d5ac70f0Sopenharmony_ci snd_pcm_direct_client_discard(dsnoop); 380d5ac70f0Sopenharmony_ci if (snd_pcm_direct_shm_discard(dsnoop)) { 381d5ac70f0Sopenharmony_ci if (snd_pcm_direct_semaphore_discard(dsnoop)) 382d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT); 383d5ac70f0Sopenharmony_ci } else 384d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT); 385d5ac70f0Sopenharmony_ci free(dsnoop->bindings); 386d5ac70f0Sopenharmony_ci pcm->private_data = NULL; 387d5ac70f0Sopenharmony_ci free(dsnoop); 388d5ac70f0Sopenharmony_ci return 0; 389d5ac70f0Sopenharmony_ci} 390d5ac70f0Sopenharmony_ci 391d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dsnoop_mmap_commit(snd_pcm_t *pcm, 392d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, 393d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 394d5ac70f0Sopenharmony_ci{ 395d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 396d5ac70f0Sopenharmony_ci int err; 397d5ac70f0Sopenharmony_ci 398d5ac70f0Sopenharmony_ci err = snd_pcm_direct_check_xrun(dsnoop, pcm); 399d5ac70f0Sopenharmony_ci if (err < 0) 400d5ac70f0Sopenharmony_ci return err; 401d5ac70f0Sopenharmony_ci if (dsnoop->state == SND_PCM_STATE_RUNNING) { 402d5ac70f0Sopenharmony_ci err = snd_pcm_dsnoop_sync_ptr(pcm); 403d5ac70f0Sopenharmony_ci if (err < 0) 404d5ac70f0Sopenharmony_ci return err; 405d5ac70f0Sopenharmony_ci } 406d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, size); 407d5ac70f0Sopenharmony_ci /* clear timer queue to avoid a bogus return from poll */ 408d5ac70f0Sopenharmony_ci if (snd_pcm_mmap_capture_avail(pcm) < pcm->avail_min) 409d5ac70f0Sopenharmony_ci snd_pcm_direct_clear_timer_queue(dsnoop); 410d5ac70f0Sopenharmony_ci return size; 411d5ac70f0Sopenharmony_ci} 412d5ac70f0Sopenharmony_ci 413d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_dsnoop_avail_update(snd_pcm_t *pcm) 414d5ac70f0Sopenharmony_ci{ 415d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 416d5ac70f0Sopenharmony_ci int err; 417d5ac70f0Sopenharmony_ci 418d5ac70f0Sopenharmony_ci if (dsnoop->state == SND_PCM_STATE_RUNNING) { 419d5ac70f0Sopenharmony_ci err = snd_pcm_dsnoop_sync_ptr(pcm); 420d5ac70f0Sopenharmony_ci if (err < 0) 421d5ac70f0Sopenharmony_ci return err; 422d5ac70f0Sopenharmony_ci } 423d5ac70f0Sopenharmony_ci if (dsnoop->state == SND_PCM_STATE_XRUN) 424d5ac70f0Sopenharmony_ci return -EPIPE; 425d5ac70f0Sopenharmony_ci 426d5ac70f0Sopenharmony_ci return snd_pcm_mmap_capture_avail(pcm); 427d5ac70f0Sopenharmony_ci} 428d5ac70f0Sopenharmony_ci 429d5ac70f0Sopenharmony_cistatic int snd_pcm_dsnoop_htimestamp(snd_pcm_t *pcm, 430d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *avail, 431d5ac70f0Sopenharmony_ci snd_htimestamp_t *tstamp) 432d5ac70f0Sopenharmony_ci{ 433d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 434d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail1; 435d5ac70f0Sopenharmony_ci int ok = 0; 436d5ac70f0Sopenharmony_ci 437d5ac70f0Sopenharmony_ci while (1) { 438d5ac70f0Sopenharmony_ci if (dsnoop->state == SND_PCM_STATE_RUNNING || 439d5ac70f0Sopenharmony_ci dsnoop->state == SND_PCM_STATE_DRAINING) 440d5ac70f0Sopenharmony_ci snd_pcm_dsnoop_sync_ptr(pcm); 441d5ac70f0Sopenharmony_ci avail1 = snd_pcm_mmap_capture_avail(pcm); 442d5ac70f0Sopenharmony_ci if (ok && *avail == avail1) 443d5ac70f0Sopenharmony_ci break; 444d5ac70f0Sopenharmony_ci *avail = avail1; 445d5ac70f0Sopenharmony_ci *tstamp = snd_pcm_hw_fast_tstamp(dsnoop->spcm); 446d5ac70f0Sopenharmony_ci ok = 1; 447d5ac70f0Sopenharmony_ci } 448d5ac70f0Sopenharmony_ci return 0; 449d5ac70f0Sopenharmony_ci} 450d5ac70f0Sopenharmony_ci 451d5ac70f0Sopenharmony_cistatic void snd_pcm_dsnoop_dump(snd_pcm_t *pcm, snd_output_t *out) 452d5ac70f0Sopenharmony_ci{ 453d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop = pcm->private_data; 454d5ac70f0Sopenharmony_ci 455d5ac70f0Sopenharmony_ci snd_output_printf(out, "Direct Snoop PCM\n"); 456d5ac70f0Sopenharmony_ci if (pcm->setup) { 457d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 458d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 459d5ac70f0Sopenharmony_ci } 460d5ac70f0Sopenharmony_ci if (dsnoop->spcm) 461d5ac70f0Sopenharmony_ci snd_pcm_dump(dsnoop->spcm, out); 462d5ac70f0Sopenharmony_ci} 463d5ac70f0Sopenharmony_ci 464d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_dsnoop_ops = { 465d5ac70f0Sopenharmony_ci .close = snd_pcm_dsnoop_close, 466d5ac70f0Sopenharmony_ci .info = snd_pcm_direct_info, 467d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_direct_hw_refine, 468d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_direct_hw_params, 469d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_direct_hw_free, 470d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_direct_sw_params, 471d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_direct_channel_info, 472d5ac70f0Sopenharmony_ci .dump = snd_pcm_dsnoop_dump, 473d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_direct_nonblock, 474d5ac70f0Sopenharmony_ci .async = snd_pcm_direct_async, 475d5ac70f0Sopenharmony_ci .mmap = snd_pcm_direct_mmap, 476d5ac70f0Sopenharmony_ci .munmap = snd_pcm_direct_munmap, 477d5ac70f0Sopenharmony_ci .query_chmaps = snd_pcm_direct_query_chmaps, 478d5ac70f0Sopenharmony_ci .get_chmap = snd_pcm_direct_get_chmap, 479d5ac70f0Sopenharmony_ci .set_chmap = snd_pcm_direct_set_chmap, 480d5ac70f0Sopenharmony_ci}; 481d5ac70f0Sopenharmony_ci 482d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = { 483d5ac70f0Sopenharmony_ci .status = snd_pcm_dsnoop_status, 484d5ac70f0Sopenharmony_ci .state = snd_pcm_dsnoop_state, 485d5ac70f0Sopenharmony_ci .hwsync = snd_pcm_dsnoop_hwsync, 486d5ac70f0Sopenharmony_ci .delay = snd_pcm_dsnoop_delay, 487d5ac70f0Sopenharmony_ci .prepare = snd_pcm_direct_prepare, 488d5ac70f0Sopenharmony_ci .reset = snd_pcm_dsnoop_reset, 489d5ac70f0Sopenharmony_ci .start = snd_pcm_dsnoop_start, 490d5ac70f0Sopenharmony_ci .drop = snd_pcm_dsnoop_drop, 491d5ac70f0Sopenharmony_ci .drain = snd_pcm_dsnoop_drain, 492d5ac70f0Sopenharmony_ci .pause = snd_pcm_dsnoop_pause, 493d5ac70f0Sopenharmony_ci .rewindable = snd_pcm_dsnoop_rewindable, 494d5ac70f0Sopenharmony_ci .rewind = snd_pcm_dsnoop_rewind, 495d5ac70f0Sopenharmony_ci .forwardable = snd_pcm_dsnoop_forwardable, 496d5ac70f0Sopenharmony_ci .forward = snd_pcm_dsnoop_forward, 497d5ac70f0Sopenharmony_ci .resume = snd_pcm_direct_resume, 498d5ac70f0Sopenharmony_ci .link = NULL, 499d5ac70f0Sopenharmony_ci .link_slaves = NULL, 500d5ac70f0Sopenharmony_ci .unlink = NULL, 501d5ac70f0Sopenharmony_ci .writei = snd_pcm_dsnoop_writei, 502d5ac70f0Sopenharmony_ci .writen = snd_pcm_dsnoop_writen, 503d5ac70f0Sopenharmony_ci .readi = snd_pcm_mmap_readi, 504d5ac70f0Sopenharmony_ci .readn = snd_pcm_mmap_readn, 505d5ac70f0Sopenharmony_ci .avail_update = snd_pcm_dsnoop_avail_update, 506d5ac70f0Sopenharmony_ci .mmap_commit = snd_pcm_dsnoop_mmap_commit, 507d5ac70f0Sopenharmony_ci .htimestamp = snd_pcm_dsnoop_htimestamp, 508d5ac70f0Sopenharmony_ci .poll_descriptors = snd_pcm_direct_poll_descriptors, 509d5ac70f0Sopenharmony_ci .poll_descriptors_count = NULL, 510d5ac70f0Sopenharmony_ci .poll_revents = snd_pcm_direct_poll_revents, 511d5ac70f0Sopenharmony_ci}; 512d5ac70f0Sopenharmony_ci 513d5ac70f0Sopenharmony_ci/** 514d5ac70f0Sopenharmony_ci * \brief Creates a new dsnoop PCM 515d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 516d5ac70f0Sopenharmony_ci * \param name Name of PCM 517d5ac70f0Sopenharmony_ci * \param opts Direct PCM configurations 518d5ac70f0Sopenharmony_ci * \param params Parameters for slave 519d5ac70f0Sopenharmony_ci * \param root Configuration root 520d5ac70f0Sopenharmony_ci * \param sconf Slave configuration 521d5ac70f0Sopenharmony_ci * \param stream PCM Direction (stream) 522d5ac70f0Sopenharmony_ci * \param mode PCM Mode 523d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 524d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 525d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 526d5ac70f0Sopenharmony_ci * changed in future. 527d5ac70f0Sopenharmony_ci */ 528d5ac70f0Sopenharmony_ciint snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, 529d5ac70f0Sopenharmony_ci struct snd_pcm_direct_open_conf *opts, 530d5ac70f0Sopenharmony_ci struct slave_params *params, 531d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *sconf, 532d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 533d5ac70f0Sopenharmony_ci{ 534d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, *spcm = NULL; 535d5ac70f0Sopenharmony_ci snd_pcm_direct_t *dsnoop; 536d5ac70f0Sopenharmony_ci int ret, first_instance; 537d5ac70f0Sopenharmony_ci 538d5ac70f0Sopenharmony_ci assert(pcmp); 539d5ac70f0Sopenharmony_ci 540d5ac70f0Sopenharmony_ci if (stream != SND_PCM_STREAM_CAPTURE) { 541d5ac70f0Sopenharmony_ci SNDERR("The dsnoop plugin supports only capture stream"); 542d5ac70f0Sopenharmony_ci return -EINVAL; 543d5ac70f0Sopenharmony_ci } 544d5ac70f0Sopenharmony_ci 545d5ac70f0Sopenharmony_ci ret = _snd_pcm_direct_new(&pcm, &dsnoop, SND_PCM_TYPE_DSNOOP, name, opts, params, stream, mode); 546d5ac70f0Sopenharmony_ci if (ret < 0) 547d5ac70f0Sopenharmony_ci return ret; 548d5ac70f0Sopenharmony_ci first_instance = ret; 549d5ac70f0Sopenharmony_ci 550d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_dsnoop_ops; 551d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_dsnoop_fast_ops; 552d5ac70f0Sopenharmony_ci pcm->private_data = dsnoop; 553d5ac70f0Sopenharmony_ci dsnoop->state = SND_PCM_STATE_OPEN; 554d5ac70f0Sopenharmony_ci dsnoop->slowptr = opts->slowptr; 555d5ac70f0Sopenharmony_ci dsnoop->max_periods = opts->max_periods; 556d5ac70f0Sopenharmony_ci dsnoop->var_periodsize = opts->var_periodsize; 557d5ac70f0Sopenharmony_ci dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr; 558d5ac70f0Sopenharmony_ci dsnoop->hw_ptr_alignment = opts->hw_ptr_alignment; 559d5ac70f0Sopenharmony_ci 560d5ac70f0Sopenharmony_ci retry: 561d5ac70f0Sopenharmony_ci if (first_instance) { 562d5ac70f0Sopenharmony_ci /* recursion is already checked in 563d5ac70f0Sopenharmony_ci snd_pcm_direct_get_slave_ipc_offset() */ 564d5ac70f0Sopenharmony_ci ret = snd_pcm_open_slave(&spcm, root, sconf, stream, 565d5ac70f0Sopenharmony_ci mode | SND_PCM_NONBLOCK, NULL); 566d5ac70f0Sopenharmony_ci if (ret < 0) { 567d5ac70f0Sopenharmony_ci SNDERR("unable to open slave"); 568d5ac70f0Sopenharmony_ci goto _err; 569d5ac70f0Sopenharmony_ci } 570d5ac70f0Sopenharmony_ci 571d5ac70f0Sopenharmony_ci if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { 572d5ac70f0Sopenharmony_ci SNDERR("dsnoop plugin can be only connected to hw plugin"); 573d5ac70f0Sopenharmony_ci goto _err; 574d5ac70f0Sopenharmony_ci } 575d5ac70f0Sopenharmony_ci 576d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_initialize_slave(dsnoop, spcm, params); 577d5ac70f0Sopenharmony_ci if (ret < 0) { 578d5ac70f0Sopenharmony_ci SNDERR("unable to initialize slave"); 579d5ac70f0Sopenharmony_ci goto _err; 580d5ac70f0Sopenharmony_ci } 581d5ac70f0Sopenharmony_ci 582d5ac70f0Sopenharmony_ci dsnoop->spcm = spcm; 583d5ac70f0Sopenharmony_ci 584d5ac70f0Sopenharmony_ci if (dsnoop->shmptr->use_server) { 585d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_server_create(dsnoop); 586d5ac70f0Sopenharmony_ci if (ret < 0) { 587d5ac70f0Sopenharmony_ci SNDERR("unable to create server"); 588d5ac70f0Sopenharmony_ci goto _err; 589d5ac70f0Sopenharmony_ci } 590d5ac70f0Sopenharmony_ci } 591d5ac70f0Sopenharmony_ci 592d5ac70f0Sopenharmony_ci dsnoop->shmptr->type = spcm->type; 593d5ac70f0Sopenharmony_ci } else { 594d5ac70f0Sopenharmony_ci if (dsnoop->shmptr->use_server) { 595d5ac70f0Sopenharmony_ci /* up semaphore to avoid deadlock */ 596d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); 597d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_client_connect(dsnoop); 598d5ac70f0Sopenharmony_ci if (ret < 0) { 599d5ac70f0Sopenharmony_ci SNDERR("unable to connect client"); 600d5ac70f0Sopenharmony_ci goto _err_nosem; 601d5ac70f0Sopenharmony_ci } 602d5ac70f0Sopenharmony_ci 603d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT); 604d5ac70f0Sopenharmony_ci 605d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client"); 606d5ac70f0Sopenharmony_ci if (ret < 0) 607d5ac70f0Sopenharmony_ci goto _err; 608d5ac70f0Sopenharmony_ci } else { 609d5ac70f0Sopenharmony_ci 610d5ac70f0Sopenharmony_ci ret = snd_pcm_open_slave(&spcm, root, sconf, stream, 611d5ac70f0Sopenharmony_ci mode | SND_PCM_NONBLOCK | 612d5ac70f0Sopenharmony_ci SND_PCM_APPEND, 613d5ac70f0Sopenharmony_ci NULL); 614d5ac70f0Sopenharmony_ci if (ret < 0) { 615d5ac70f0Sopenharmony_ci /* all other streams have been closed; 616d5ac70f0Sopenharmony_ci * retry as the first instance 617d5ac70f0Sopenharmony_ci */ 618d5ac70f0Sopenharmony_ci if (ret == -EBADFD) { 619d5ac70f0Sopenharmony_ci first_instance = 1; 620d5ac70f0Sopenharmony_ci goto retry; 621d5ac70f0Sopenharmony_ci } 622d5ac70f0Sopenharmony_ci SNDERR("unable to open slave"); 623d5ac70f0Sopenharmony_ci goto _err; 624d5ac70f0Sopenharmony_ci } 625d5ac70f0Sopenharmony_ci if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { 626d5ac70f0Sopenharmony_ci SNDERR("dsnoop plugin can be only connected to hw plugin"); 627d5ac70f0Sopenharmony_ci ret = -EINVAL; 628d5ac70f0Sopenharmony_ci goto _err; 629d5ac70f0Sopenharmony_ci } 630d5ac70f0Sopenharmony_ci 631d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_initialize_secondary_slave(dsnoop, spcm, params); 632d5ac70f0Sopenharmony_ci if (ret < 0) { 633d5ac70f0Sopenharmony_ci SNDERR("unable to initialize slave"); 634d5ac70f0Sopenharmony_ci goto _err; 635d5ac70f0Sopenharmony_ci } 636d5ac70f0Sopenharmony_ci } 637d5ac70f0Sopenharmony_ci 638d5ac70f0Sopenharmony_ci dsnoop->spcm = spcm; 639d5ac70f0Sopenharmony_ci } 640d5ac70f0Sopenharmony_ci 641d5ac70f0Sopenharmony_ci ret = snd_pcm_direct_initialize_poll_fd(dsnoop); 642d5ac70f0Sopenharmony_ci if (ret < 0) { 643d5ac70f0Sopenharmony_ci SNDERR("unable to initialize poll_fd"); 644d5ac70f0Sopenharmony_ci goto _err; 645d5ac70f0Sopenharmony_ci } 646d5ac70f0Sopenharmony_ci 647d5ac70f0Sopenharmony_ci pcm->poll_fd = dsnoop->poll_fd; 648d5ac70f0Sopenharmony_ci pcm->poll_events = POLLIN; /* it's different than other plugins */ 649d5ac70f0Sopenharmony_ci pcm->tstamp_type = spcm->tstamp_type; 650d5ac70f0Sopenharmony_ci pcm->mmap_rw = 1; 651d5ac70f0Sopenharmony_ci snd_pcm_set_hw_ptr(pcm, &dsnoop->hw_ptr, -1, 0); 652d5ac70f0Sopenharmony_ci snd_pcm_set_appl_ptr(pcm, &dsnoop->appl_ptr, -1, 0); 653d5ac70f0Sopenharmony_ci 654d5ac70f0Sopenharmony_ci if (dsnoop->channels == UINT_MAX) 655d5ac70f0Sopenharmony_ci dsnoop->channels = dsnoop->shmptr->s.channels; 656d5ac70f0Sopenharmony_ci 657d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); 658d5ac70f0Sopenharmony_ci 659d5ac70f0Sopenharmony_ci *pcmp = pcm; 660d5ac70f0Sopenharmony_ci return 0; 661d5ac70f0Sopenharmony_ci 662d5ac70f0Sopenharmony_ci _err: 663d5ac70f0Sopenharmony_ci if (dsnoop->timer) 664d5ac70f0Sopenharmony_ci snd_timer_close(dsnoop->timer); 665d5ac70f0Sopenharmony_ci if (dsnoop->server) 666d5ac70f0Sopenharmony_ci snd_pcm_direct_server_discard(dsnoop); 667d5ac70f0Sopenharmony_ci if (dsnoop->client) 668d5ac70f0Sopenharmony_ci snd_pcm_direct_client_discard(dsnoop); 669d5ac70f0Sopenharmony_ci if (spcm) 670d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 671d5ac70f0Sopenharmony_ci if ((dsnoop->shmid >= 0) && (snd_pcm_direct_shm_discard(dsnoop))) { 672d5ac70f0Sopenharmony_ci if (snd_pcm_direct_semaphore_discard(dsnoop)) 673d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_final(dsnoop, DIRECT_IPC_SEM_CLIENT); 674d5ac70f0Sopenharmony_ci } else 675d5ac70f0Sopenharmony_ci snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); 676d5ac70f0Sopenharmony_ci 677d5ac70f0Sopenharmony_ci _err_nosem: 678d5ac70f0Sopenharmony_ci free(dsnoop->bindings); 679d5ac70f0Sopenharmony_ci free(dsnoop); 680d5ac70f0Sopenharmony_ci snd_pcm_free(pcm); 681d5ac70f0Sopenharmony_ci return ret; 682d5ac70f0Sopenharmony_ci} 683d5ac70f0Sopenharmony_ci 684d5ac70f0Sopenharmony_ci/*! \page pcm_plugins 685d5ac70f0Sopenharmony_ci 686d5ac70f0Sopenharmony_ci\section pcm_plugins_dsnoop Plugin: dsnoop 687d5ac70f0Sopenharmony_ci 688d5ac70f0Sopenharmony_ciThis plugin splits one capture stream to more. 689d5ac70f0Sopenharmony_ciIt works the reverse way of \ref pcm_plugins_dmix "dmix plugin", 690d5ac70f0Sopenharmony_cireading the shared capture buffer from many clients concurrently. 691d5ac70f0Sopenharmony_ciThe meaning of parameters below are almost identical with 692d5ac70f0Sopenharmony_cidmix plugin. 693d5ac70f0Sopenharmony_ci 694d5ac70f0Sopenharmony_ci\code 695d5ac70f0Sopenharmony_cipcm.name { 696d5ac70f0Sopenharmony_ci type dsnoop # Direct snoop 697d5ac70f0Sopenharmony_ci ipc_key INT # unique IPC key 698d5ac70f0Sopenharmony_ci ipc_key_add_uid BOOL # add current uid to unique IPC key 699d5ac70f0Sopenharmony_ci ipc_perm INT # IPC permissions (octal, default 0600) 700d5ac70f0Sopenharmony_ci hw_ptr_alignment STR # Slave application and hw pointer alignment type 701d5ac70f0Sopenharmony_ci # STR can be one of the below strings : 702d5ac70f0Sopenharmony_ci # no (or off) 703d5ac70f0Sopenharmony_ci # roundup 704d5ac70f0Sopenharmony_ci # rounddown 705d5ac70f0Sopenharmony_ci # auto (default) 706d5ac70f0Sopenharmony_ci tstamp_type STR # timestamp type 707d5ac70f0Sopenharmony_ci # STR can be one of the below strings : 708d5ac70f0Sopenharmony_ci # default, gettimeofday, monotonic, monotonic_raw 709d5ac70f0Sopenharmony_ci slave STR 710d5ac70f0Sopenharmony_ci # or 711d5ac70f0Sopenharmony_ci slave { # Slave definition 712d5ac70f0Sopenharmony_ci pcm STR # slave PCM name 713d5ac70f0Sopenharmony_ci # or 714d5ac70f0Sopenharmony_ci pcm { } # slave PCM definition 715d5ac70f0Sopenharmony_ci format STR # format definition 716d5ac70f0Sopenharmony_ci rate INT # rate definition 717d5ac70f0Sopenharmony_ci channels INT 718d5ac70f0Sopenharmony_ci period_time INT # in usec 719d5ac70f0Sopenharmony_ci # or 720d5ac70f0Sopenharmony_ci period_size INT # in frames 721d5ac70f0Sopenharmony_ci buffer_time INT # in usec 722d5ac70f0Sopenharmony_ci # or 723d5ac70f0Sopenharmony_ci buffer_size INT # in frames 724d5ac70f0Sopenharmony_ci periods INT # when buffer_size or buffer_time is not specified 725d5ac70f0Sopenharmony_ci } 726d5ac70f0Sopenharmony_ci bindings { # note: this is client independent!!! 727d5ac70f0Sopenharmony_ci N INT # maps slave channel to client channel N 728d5ac70f0Sopenharmony_ci } 729d5ac70f0Sopenharmony_ci slowptr BOOL # slow but more precise pointer updates 730d5ac70f0Sopenharmony_ci} 731d5ac70f0Sopenharmony_ci\endcode 732d5ac70f0Sopenharmony_ci 733d5ac70f0Sopenharmony_ci<code>hw_ptr_alignment</code> specifies slave application and hw 734d5ac70f0Sopenharmony_cipointer alignment type. By default hw_ptr_alignment is auto. Below are 735d5ac70f0Sopenharmony_cithe possible configurations: 736d5ac70f0Sopenharmony_ci- no: minimal latency with minimal frames dropped at startup. But 737d5ac70f0Sopenharmony_ci wakeup of application (return from snd_pcm_wait() or poll()) can 738d5ac70f0Sopenharmony_ci take up to 2 * period. 739d5ac70f0Sopenharmony_ci- roundup: It is guaranteed that all frames will be played at 740d5ac70f0Sopenharmony_ci startup. But the latency will increase upto period-1 frames. 741d5ac70f0Sopenharmony_ci- rounddown: It is guaranteed that a wakeup will happen for each 742d5ac70f0Sopenharmony_ci period and frames can be written from application. But on startup 743d5ac70f0Sopenharmony_ci upto period-1 frames will be dropped. 744d5ac70f0Sopenharmony_ci- auto: Selects the best approach depending on the used period and 745d5ac70f0Sopenharmony_ci buffer size. 746d5ac70f0Sopenharmony_ci If the application buffer size is < 2 * application period, 747d5ac70f0Sopenharmony_ci "roundup" will be selected to avoid over runs. If the slave_period 748d5ac70f0Sopenharmony_ci is < 10ms we could expect that there are low latency 749d5ac70f0Sopenharmony_ci requirements. Therefore "rounddown" will be chosen to avoid long 750d5ac70f0Sopenharmony_ci wakeup times. Else "no" will be chosen. 751d5ac70f0Sopenharmony_ci 752d5ac70f0Sopenharmony_ci\subsection pcm_plugins_dsnoop_funcref Function reference 753d5ac70f0Sopenharmony_ci 754d5ac70f0Sopenharmony_ci<UL> 755d5ac70f0Sopenharmony_ci <LI>snd_pcm_dsnoop_open() 756d5ac70f0Sopenharmony_ci <LI>_snd_pcm_dsnoop_open() 757d5ac70f0Sopenharmony_ci</UL> 758d5ac70f0Sopenharmony_ci 759d5ac70f0Sopenharmony_ci*/ 760d5ac70f0Sopenharmony_ci 761d5ac70f0Sopenharmony_ci/** 762d5ac70f0Sopenharmony_ci * \brief Creates a new dsnoop PCM 763d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 764d5ac70f0Sopenharmony_ci * \param name Name of PCM 765d5ac70f0Sopenharmony_ci * \param root Root configuration node 766d5ac70f0Sopenharmony_ci * \param conf Configuration node with dsnoop PCM description 767d5ac70f0Sopenharmony_ci * \param stream PCM Stream 768d5ac70f0Sopenharmony_ci * \param mode PCM Mode 769d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 770d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 771d5ac70f0Sopenharmony_ci * changed in future. 772d5ac70f0Sopenharmony_ci */ 773d5ac70f0Sopenharmony_ciint _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, 774d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *conf, 775d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 776d5ac70f0Sopenharmony_ci{ 777d5ac70f0Sopenharmony_ci snd_config_t *sconf; 778d5ac70f0Sopenharmony_ci struct slave_params params; 779d5ac70f0Sopenharmony_ci struct snd_pcm_direct_open_conf dopen; 780d5ac70f0Sopenharmony_ci int bsize, psize; 781d5ac70f0Sopenharmony_ci int err; 782d5ac70f0Sopenharmony_ci 783d5ac70f0Sopenharmony_ci err = snd_pcm_direct_parse_open_conf(root, conf, stream, &dopen); 784d5ac70f0Sopenharmony_ci if (err < 0) 785d5ac70f0Sopenharmony_ci return err; 786d5ac70f0Sopenharmony_ci 787d5ac70f0Sopenharmony_ci /* the default settings, it might be invalid for some hardware */ 788d5ac70f0Sopenharmony_ci params.format = SND_PCM_FORMAT_S16; 789d5ac70f0Sopenharmony_ci params.rate = 48000; 790d5ac70f0Sopenharmony_ci params.channels = 2; 791d5ac70f0Sopenharmony_ci params.period_time = -1; 792d5ac70f0Sopenharmony_ci params.buffer_time = -1; 793d5ac70f0Sopenharmony_ci bsize = psize = -1; 794d5ac70f0Sopenharmony_ci params.periods = 3; 795d5ac70f0Sopenharmony_ci err = snd_pcm_slave_conf(root, dopen.slave, &sconf, 8, 796d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FORMAT, SCONF_UNCHANGED, ¶ms.format, 797d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate, 798d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels, 799d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time, 800d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time, 801d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize, 802d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize, 803d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods); 804d5ac70f0Sopenharmony_ci if (err < 0) 805d5ac70f0Sopenharmony_ci return err; 806d5ac70f0Sopenharmony_ci 807d5ac70f0Sopenharmony_ci /* set a reasonable default */ 808d5ac70f0Sopenharmony_ci if (psize == -1 && params.period_time == -1) 809d5ac70f0Sopenharmony_ci params.period_time = 125000; /* 0.125 seconds */ 810d5ac70f0Sopenharmony_ci 811d5ac70f0Sopenharmony_ci if (params.format == -2) 812d5ac70f0Sopenharmony_ci params.format = SND_PCM_FORMAT_UNKNOWN; 813d5ac70f0Sopenharmony_ci 814d5ac70f0Sopenharmony_ci params.period_size = psize; 815d5ac70f0Sopenharmony_ci params.buffer_size = bsize; 816d5ac70f0Sopenharmony_ci 817d5ac70f0Sopenharmony_ci err = snd_pcm_dsnoop_open(pcmp, name, &dopen, ¶ms, 818d5ac70f0Sopenharmony_ci root, sconf, stream, mode); 819d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 820d5ac70f0Sopenharmony_ci return err; 821d5ac70f0Sopenharmony_ci} 822d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 823d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_dsnoop_open, SND_PCM_DLSYM_VERSION); 824d5ac70f0Sopenharmony_ci#endif 825