1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_ioplug.c 3d5ac70f0Sopenharmony_ci * \ingroup Plugin_SDK 4d5ac70f0Sopenharmony_ci * \brief I/O Plugin SDK 5d5ac70f0Sopenharmony_ci * \author Takashi Iwai <tiwai@suse.de> 6d5ac70f0Sopenharmony_ci * \date 2005 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * PCM - External I/O Plugin SDK 10d5ac70f0Sopenharmony_ci * Copyright (c) 2005 by Takashi Iwai <tiwai@suse.de> 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 "pcm_ioplug.h" 31d5ac70f0Sopenharmony_ci#include "pcm_ext_parm.h" 32d5ac70f0Sopenharmony_ci#include "pcm_generic.h" 33d5ac70f0Sopenharmony_ci 34d5ac70f0Sopenharmony_ci#ifndef PIC 35d5ac70f0Sopenharmony_ci/* entry for static linking */ 36d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_ioplug = ""; 37d5ac70f0Sopenharmony_ci#endif 38d5ac70f0Sopenharmony_ci 39d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 40d5ac70f0Sopenharmony_ci 41d5ac70f0Sopenharmony_ci/* hw_params */ 42d5ac70f0Sopenharmony_citypedef struct snd_pcm_ioplug_priv { 43d5ac70f0Sopenharmony_ci snd_pcm_ioplug_t *data; 44d5ac70f0Sopenharmony_ci struct snd_ext_parm params[SND_PCM_IOPLUG_HW_PARAMS]; 45d5ac70f0Sopenharmony_ci snd_pcm_uframes_t last_hw; 46d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail_max; 47d5ac70f0Sopenharmony_ci snd_htimestamp_t trigger_tstamp; 48d5ac70f0Sopenharmony_ci} ioplug_priv_t; 49d5ac70f0Sopenharmony_ci 50d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_drop(snd_pcm_t *pcm); 51d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm); 52d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space); 53d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); 54d5ac70f0Sopenharmony_ci 55d5ac70f0Sopenharmony_ci/* update the hw pointer */ 56d5ac70f0Sopenharmony_ci/* called in lock */ 57d5ac70f0Sopenharmony_cistatic void snd_pcm_ioplug_hw_ptr_update(snd_pcm_t *pcm) 58d5ac70f0Sopenharmony_ci{ 59d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 60d5ac70f0Sopenharmony_ci snd_pcm_sframes_t hw; 61d5ac70f0Sopenharmony_ci 62d5ac70f0Sopenharmony_ci hw = io->data->callback->pointer(io->data); 63d5ac70f0Sopenharmony_ci if (hw >= 0) { 64d5ac70f0Sopenharmony_ci snd_pcm_uframes_t delta; 65d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail; 66d5ac70f0Sopenharmony_ci 67d5ac70f0Sopenharmony_ci if ((snd_pcm_uframes_t)hw >= io->last_hw) 68d5ac70f0Sopenharmony_ci delta = hw - io->last_hw; 69d5ac70f0Sopenharmony_ci else { 70d5ac70f0Sopenharmony_ci const snd_pcm_uframes_t wrap_point = 71d5ac70f0Sopenharmony_ci (io->data->flags & SND_PCM_IOPLUG_FLAG_BOUNDARY_WA) ? 72d5ac70f0Sopenharmony_ci pcm->boundary : pcm->buffer_size; 73d5ac70f0Sopenharmony_ci delta = wrap_point + hw - io->last_hw; 74d5ac70f0Sopenharmony_ci } 75d5ac70f0Sopenharmony_ci snd_pcm_mmap_hw_forward(io->data->pcm, delta); 76d5ac70f0Sopenharmony_ci /* stop the stream if all samples are drained */ 77d5ac70f0Sopenharmony_ci if (io->data->state == SND_PCM_STATE_DRAINING) { 78d5ac70f0Sopenharmony_ci avail = snd_pcm_mmap_avail(pcm); 79d5ac70f0Sopenharmony_ci if (avail >= pcm->buffer_size) 80d5ac70f0Sopenharmony_ci snd_pcm_ioplug_drop(pcm); 81d5ac70f0Sopenharmony_ci } 82d5ac70f0Sopenharmony_ci io->last_hw = (snd_pcm_uframes_t)hw; 83d5ac70f0Sopenharmony_ci } else { 84d5ac70f0Sopenharmony_ci if (io->data->state == SND_PCM_STATE_DRAINING) 85d5ac70f0Sopenharmony_ci snd_pcm_ioplug_drop(pcm); 86d5ac70f0Sopenharmony_ci else 87d5ac70f0Sopenharmony_ci io->data->state = SNDRV_PCM_STATE_XRUN; 88d5ac70f0Sopenharmony_ci } 89d5ac70f0Sopenharmony_ci} 90d5ac70f0Sopenharmony_ci 91d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_info(snd_pcm_t *pcm, snd_pcm_info_t *info) 92d5ac70f0Sopenharmony_ci{ 93d5ac70f0Sopenharmony_ci memset(info, 0, sizeof(*info)); 94d5ac70f0Sopenharmony_ci info->stream = pcm->stream; 95d5ac70f0Sopenharmony_ci info->card = -1; 96d5ac70f0Sopenharmony_ci if (pcm->name) { 97d5ac70f0Sopenharmony_ci snd_strlcpy((char *)info->id, pcm->name, sizeof(info->id)); 98d5ac70f0Sopenharmony_ci snd_strlcpy((char *)info->name, pcm->name, sizeof(info->name)); 99d5ac70f0Sopenharmony_ci snd_strlcpy((char *)info->subname, pcm->name, sizeof(info->subname)); 100d5ac70f0Sopenharmony_ci } 101d5ac70f0Sopenharmony_ci info->subdevices_count = 1; 102d5ac70f0Sopenharmony_ci return 0; 103d5ac70f0Sopenharmony_ci} 104d5ac70f0Sopenharmony_ci 105d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) 106d5ac70f0Sopenharmony_ci{ 107d5ac70f0Sopenharmony_ci return snd_pcm_channel_info_shm(pcm, info, -1); 108d5ac70f0Sopenharmony_ci} 109d5ac70f0Sopenharmony_ci 110d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 111d5ac70f0Sopenharmony_ci{ 112d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 113d5ac70f0Sopenharmony_ci 114d5ac70f0Sopenharmony_ci if (io->data->version >= 0x010001 && 115d5ac70f0Sopenharmony_ci io->data->callback->delay) 116d5ac70f0Sopenharmony_ci return io->data->callback->delay(io->data, delayp); 117d5ac70f0Sopenharmony_ci else { 118d5ac70f0Sopenharmony_ci snd_pcm_ioplug_hw_ptr_update(pcm); 119d5ac70f0Sopenharmony_ci *delayp = snd_pcm_mmap_delay(pcm); 120d5ac70f0Sopenharmony_ci } 121d5ac70f0Sopenharmony_ci return 0; 122d5ac70f0Sopenharmony_ci} 123d5ac70f0Sopenharmony_ci 124d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_status(snd_pcm_t *pcm, snd_pcm_status_t * status) 125d5ac70f0Sopenharmony_ci{ 126d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 127d5ac70f0Sopenharmony_ci snd_pcm_sframes_t sd; 128d5ac70f0Sopenharmony_ci 129d5ac70f0Sopenharmony_ci memset(status, 0, sizeof(*status)); 130d5ac70f0Sopenharmony_ci snd_pcm_ioplug_hw_ptr_update(pcm); 131d5ac70f0Sopenharmony_ci status->state = io->data->state; 132d5ac70f0Sopenharmony_ci status->trigger_tstamp = io->trigger_tstamp; 133d5ac70f0Sopenharmony_ci gettimestamp(&status->tstamp, pcm->tstamp_type); 134d5ac70f0Sopenharmony_ci status->avail = snd_pcm_mmap_avail(pcm); 135d5ac70f0Sopenharmony_ci status->avail_max = io->avail_max; 136d5ac70f0Sopenharmony_ci status->appl_ptr = *pcm->appl.ptr; 137d5ac70f0Sopenharmony_ci status->hw_ptr = *pcm->hw.ptr; 138d5ac70f0Sopenharmony_ci if (snd_pcm_ioplug_delay(pcm, &sd) < 0) 139d5ac70f0Sopenharmony_ci sd = snd_pcm_mmap_delay(pcm); 140d5ac70f0Sopenharmony_ci status->delay = sd; 141d5ac70f0Sopenharmony_ci return 0; 142d5ac70f0Sopenharmony_ci} 143d5ac70f0Sopenharmony_ci 144d5ac70f0Sopenharmony_cistatic snd_pcm_state_t snd_pcm_ioplug_state(snd_pcm_t *pcm) 145d5ac70f0Sopenharmony_ci{ 146d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 147d5ac70f0Sopenharmony_ci return io->data->state; 148d5ac70f0Sopenharmony_ci} 149d5ac70f0Sopenharmony_ci 150d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_hwsync(snd_pcm_t *pcm) 151d5ac70f0Sopenharmony_ci{ 152d5ac70f0Sopenharmony_ci snd_pcm_ioplug_hw_ptr_update(pcm); 153d5ac70f0Sopenharmony_ci return 0; 154d5ac70f0Sopenharmony_ci} 155d5ac70f0Sopenharmony_ci 156d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_reset(snd_pcm_t *pcm) 157d5ac70f0Sopenharmony_ci{ 158d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 159d5ac70f0Sopenharmony_ci 160d5ac70f0Sopenharmony_ci io->data->appl_ptr = 0; 161d5ac70f0Sopenharmony_ci io->data->hw_ptr = 0; 162d5ac70f0Sopenharmony_ci io->last_hw = 0; 163d5ac70f0Sopenharmony_ci io->avail_max = 0; 164d5ac70f0Sopenharmony_ci return 0; 165d5ac70f0Sopenharmony_ci} 166d5ac70f0Sopenharmony_ci 167d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_prepare(snd_pcm_t *pcm) 168d5ac70f0Sopenharmony_ci{ 169d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 170d5ac70f0Sopenharmony_ci int err = 0; 171d5ac70f0Sopenharmony_ci 172d5ac70f0Sopenharmony_ci snd_pcm_ioplug_reset(pcm); 173d5ac70f0Sopenharmony_ci if (io->data->callback->prepare) { 174d5ac70f0Sopenharmony_ci snd_pcm_unlock(pcm); /* to avoid deadlock */ 175d5ac70f0Sopenharmony_ci err = io->data->callback->prepare(io->data); 176d5ac70f0Sopenharmony_ci snd_pcm_lock(pcm); 177d5ac70f0Sopenharmony_ci } 178d5ac70f0Sopenharmony_ci if (err < 0) 179d5ac70f0Sopenharmony_ci return err; 180d5ac70f0Sopenharmony_ci 181d5ac70f0Sopenharmony_ci io->data->state = SND_PCM_STATE_PREPARED; 182d5ac70f0Sopenharmony_ci return err; 183d5ac70f0Sopenharmony_ci} 184d5ac70f0Sopenharmony_ci 185d5ac70f0Sopenharmony_cistatic const int hw_params_type[SND_PCM_IOPLUG_HW_PARAMS] = { 186d5ac70f0Sopenharmony_ci [SND_PCM_IOPLUG_HW_ACCESS] = SND_PCM_HW_PARAM_ACCESS, 187d5ac70f0Sopenharmony_ci [SND_PCM_IOPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT, 188d5ac70f0Sopenharmony_ci [SND_PCM_IOPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS, 189d5ac70f0Sopenharmony_ci [SND_PCM_IOPLUG_HW_RATE] = SND_PCM_HW_PARAM_RATE, 190d5ac70f0Sopenharmony_ci [SND_PCM_IOPLUG_HW_PERIOD_BYTES] = SND_PCM_HW_PARAM_PERIOD_BYTES, 191d5ac70f0Sopenharmony_ci [SND_PCM_IOPLUG_HW_BUFFER_BYTES] = SND_PCM_HW_PARAM_BUFFER_BYTES, 192d5ac70f0Sopenharmony_ci [SND_PCM_IOPLUG_HW_PERIODS] = SND_PCM_HW_PARAM_PERIODS, 193d5ac70f0Sopenharmony_ci}; 194d5ac70f0Sopenharmony_ci 195d5ac70f0Sopenharmony_ci/* x = a * b */ 196d5ac70f0Sopenharmony_cistatic int rule_mul(snd_pcm_hw_params_t *params, int x, int a, int b) 197d5ac70f0Sopenharmony_ci{ 198d5ac70f0Sopenharmony_ci snd_interval_t t; 199d5ac70f0Sopenharmony_ci 200d5ac70f0Sopenharmony_ci snd_interval_mul(hw_param_interval(params, a), 201d5ac70f0Sopenharmony_ci hw_param_interval(params, b), &t); 202d5ac70f0Sopenharmony_ci return snd_interval_refine(hw_param_interval(params, x), &t); 203d5ac70f0Sopenharmony_ci} 204d5ac70f0Sopenharmony_ci 205d5ac70f0Sopenharmony_ci/* x = a / b */ 206d5ac70f0Sopenharmony_cistatic int rule_div(snd_pcm_hw_params_t *params, int x, int a, int b) 207d5ac70f0Sopenharmony_ci{ 208d5ac70f0Sopenharmony_ci snd_interval_t t; 209d5ac70f0Sopenharmony_ci 210d5ac70f0Sopenharmony_ci snd_interval_div(hw_param_interval(params, a), 211d5ac70f0Sopenharmony_ci hw_param_interval(params, b), &t); 212d5ac70f0Sopenharmony_ci return snd_interval_refine(hw_param_interval(params, x), &t); 213d5ac70f0Sopenharmony_ci} 214d5ac70f0Sopenharmony_ci 215d5ac70f0Sopenharmony_ci/* x = a * b / k */ 216d5ac70f0Sopenharmony_cistatic int rule_muldivk(snd_pcm_hw_params_t *params, int x, int a, int b, int k) 217d5ac70f0Sopenharmony_ci{ 218d5ac70f0Sopenharmony_ci snd_interval_t t; 219d5ac70f0Sopenharmony_ci 220d5ac70f0Sopenharmony_ci snd_interval_muldivk(hw_param_interval(params, a), 221d5ac70f0Sopenharmony_ci hw_param_interval(params, b), k, &t); 222d5ac70f0Sopenharmony_ci return snd_interval_refine(hw_param_interval(params, x), &t); 223d5ac70f0Sopenharmony_ci} 224d5ac70f0Sopenharmony_ci 225d5ac70f0Sopenharmony_ci/* x = a * k / b */ 226d5ac70f0Sopenharmony_cistatic int rule_mulkdiv(snd_pcm_hw_params_t *params, int x, int a, int k, int b) 227d5ac70f0Sopenharmony_ci{ 228d5ac70f0Sopenharmony_ci snd_interval_t t; 229d5ac70f0Sopenharmony_ci 230d5ac70f0Sopenharmony_ci snd_interval_mulkdiv(hw_param_interval(params, a), k, 231d5ac70f0Sopenharmony_ci hw_param_interval(params, b), &t); 232d5ac70f0Sopenharmony_ci return snd_interval_refine(hw_param_interval(params, x), &t); 233d5ac70f0Sopenharmony_ci} 234d5ac70f0Sopenharmony_ci 235d5ac70f0Sopenharmony_ci#if 0 236d5ac70f0Sopenharmony_cistatic void dump_parm(snd_pcm_hw_params_t *params) 237d5ac70f0Sopenharmony_ci{ 238d5ac70f0Sopenharmony_ci snd_output_t *log; 239d5ac70f0Sopenharmony_ci snd_output_stdio_attach(&log, stderr, 0); 240d5ac70f0Sopenharmony_ci snd_pcm_hw_params_dump(params, log); 241d5ac70f0Sopenharmony_ci snd_output_close(log); 242d5ac70f0Sopenharmony_ci} 243d5ac70f0Sopenharmony_ci#endif 244d5ac70f0Sopenharmony_ci 245d5ac70f0Sopenharmony_ci/* refine *_TIME and *_SIZE, then update *_BYTES */ 246d5ac70f0Sopenharmony_cistatic int refine_time_and_size(snd_pcm_hw_params_t *params, 247d5ac70f0Sopenharmony_ci int time, int size, int bytes) 248d5ac70f0Sopenharmony_ci{ 249d5ac70f0Sopenharmony_ci int err, change1 = 0; 250d5ac70f0Sopenharmony_ci 251d5ac70f0Sopenharmony_ci /* size = time * rate / 1000000 */ 252d5ac70f0Sopenharmony_ci err = rule_muldivk(params, size, time, 253d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_RATE, 1000000); 254d5ac70f0Sopenharmony_ci if (err < 0) 255d5ac70f0Sopenharmony_ci return err; 256d5ac70f0Sopenharmony_ci change1 |= err; 257d5ac70f0Sopenharmony_ci 258d5ac70f0Sopenharmony_ci /* bytes = size * framebits / 8 */ 259d5ac70f0Sopenharmony_ci err = rule_muldivk(params, bytes, size, 260d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FRAME_BITS, 8); 261d5ac70f0Sopenharmony_ci if (err < 0) 262d5ac70f0Sopenharmony_ci return err; 263d5ac70f0Sopenharmony_ci change1 |= err; 264d5ac70f0Sopenharmony_ci return change1; 265d5ac70f0Sopenharmony_ci} 266d5ac70f0Sopenharmony_ci 267d5ac70f0Sopenharmony_ci/* refine *_TIME and *_SIZE from *_BYTES */ 268d5ac70f0Sopenharmony_cistatic int refine_back_time_and_size(snd_pcm_hw_params_t *params, 269d5ac70f0Sopenharmony_ci int time, int size, int bytes) 270d5ac70f0Sopenharmony_ci{ 271d5ac70f0Sopenharmony_ci int err; 272d5ac70f0Sopenharmony_ci 273d5ac70f0Sopenharmony_ci /* size = bytes * 8 / framebits */ 274d5ac70f0Sopenharmony_ci err = rule_mulkdiv(params, size, bytes, 8, SND_PCM_HW_PARAM_FRAME_BITS); 275d5ac70f0Sopenharmony_ci if (err < 0) 276d5ac70f0Sopenharmony_ci return err; 277d5ac70f0Sopenharmony_ci /* time = size * 1000000 / rate */ 278d5ac70f0Sopenharmony_ci err = rule_mulkdiv(params, time, size, 1000000, SND_PCM_HW_PARAM_RATE); 279d5ac70f0Sopenharmony_ci if (err < 0) 280d5ac70f0Sopenharmony_ci return err; 281d5ac70f0Sopenharmony_ci return 0; 282d5ac70f0Sopenharmony_ci} 283d5ac70f0Sopenharmony_ci 284d5ac70f0Sopenharmony_ci 285d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 286d5ac70f0Sopenharmony_ci{ 287d5ac70f0Sopenharmony_ci int change = 0, change1, change2, err; 288d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 289d5ac70f0Sopenharmony_ci struct snd_ext_parm *p; 290d5ac70f0Sopenharmony_ci unsigned int i; 291d5ac70f0Sopenharmony_ci 292d5ac70f0Sopenharmony_ci /* access, format */ 293d5ac70f0Sopenharmony_ci for (i = SND_PCM_IOPLUG_HW_ACCESS; i <= SND_PCM_IOPLUG_HW_FORMAT; i++) { 294d5ac70f0Sopenharmony_ci err = snd_ext_parm_mask_refine(hw_param_mask(params, hw_params_type[i]), 295d5ac70f0Sopenharmony_ci io->params, i); 296d5ac70f0Sopenharmony_ci if (err < 0) 297d5ac70f0Sopenharmony_ci return err; 298d5ac70f0Sopenharmony_ci change |= err; 299d5ac70f0Sopenharmony_ci } 300d5ac70f0Sopenharmony_ci /* channels, rate */ 301d5ac70f0Sopenharmony_ci for (; i <= SND_PCM_IOPLUG_HW_RATE; i++) { 302d5ac70f0Sopenharmony_ci err = snd_ext_parm_interval_refine(hw_param_interval(params, hw_params_type[i]), 303d5ac70f0Sopenharmony_ci io->params, i); 304d5ac70f0Sopenharmony_ci if (err < 0) 305d5ac70f0Sopenharmony_ci return err; 306d5ac70f0Sopenharmony_ci change |= err; 307d5ac70f0Sopenharmony_ci } 308d5ac70f0Sopenharmony_ci 309d5ac70f0Sopenharmony_ci if (params->rmask & ((1 << SND_PCM_HW_PARAM_ACCESS) | 310d5ac70f0Sopenharmony_ci (1 << SND_PCM_HW_PARAM_FORMAT) | 311d5ac70f0Sopenharmony_ci (1 << SND_PCM_HW_PARAM_SUBFORMAT) | 312d5ac70f0Sopenharmony_ci (1 << SND_PCM_HW_PARAM_CHANNELS) | 313d5ac70f0Sopenharmony_ci (1 << SND_PCM_HW_PARAM_RATE))) { 314d5ac70f0Sopenharmony_ci err = snd_pcm_hw_refine_soft(pcm, params); 315d5ac70f0Sopenharmony_ci if (err < 0) 316d5ac70f0Sopenharmony_ci return err; 317d5ac70f0Sopenharmony_ci change |= err; 318d5ac70f0Sopenharmony_ci } 319d5ac70f0Sopenharmony_ci 320d5ac70f0Sopenharmony_ci change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME, 321d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_SIZE, 322d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_BYTES); 323d5ac70f0Sopenharmony_ci if (change1 < 0) 324d5ac70f0Sopenharmony_ci return change1; 325d5ac70f0Sopenharmony_ci err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES), 326d5ac70f0Sopenharmony_ci io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES); 327d5ac70f0Sopenharmony_ci if (err < 0) 328d5ac70f0Sopenharmony_ci return err; 329d5ac70f0Sopenharmony_ci change1 |= err; 330d5ac70f0Sopenharmony_ci if (change1) { 331d5ac70f0Sopenharmony_ci change |= change1; 332d5ac70f0Sopenharmony_ci err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME, 333d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_SIZE, 334d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_BYTES); 335d5ac70f0Sopenharmony_ci if (err < 0) 336d5ac70f0Sopenharmony_ci return err; 337d5ac70f0Sopenharmony_ci } 338d5ac70f0Sopenharmony_ci 339d5ac70f0Sopenharmony_ci change1 = refine_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME, 340d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_SIZE, 341d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_BYTES); 342d5ac70f0Sopenharmony_ci if (change1 < 0) 343d5ac70f0Sopenharmony_ci return change1; 344d5ac70f0Sopenharmony_ci change |= change1; 345d5ac70f0Sopenharmony_ci 346d5ac70f0Sopenharmony_ci do { 347d5ac70f0Sopenharmony_ci change2 = 0; 348d5ac70f0Sopenharmony_ci err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_BUFFER_BYTES), 349d5ac70f0Sopenharmony_ci io->params, SND_PCM_IOPLUG_HW_BUFFER_BYTES); 350d5ac70f0Sopenharmony_ci if (err < 0) 351d5ac70f0Sopenharmony_ci return err; 352d5ac70f0Sopenharmony_ci change2 |= err; 353d5ac70f0Sopenharmony_ci /* periods = buffer_bytes / period_bytes */ 354d5ac70f0Sopenharmony_ci err = rule_div(params, SND_PCM_HW_PARAM_PERIODS, 355d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_BYTES, 356d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_BYTES); 357d5ac70f0Sopenharmony_ci if (err < 0) 358d5ac70f0Sopenharmony_ci return err; 359d5ac70f0Sopenharmony_ci change2 |= err; 360d5ac70f0Sopenharmony_ci err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIODS), 361d5ac70f0Sopenharmony_ci io->params, SND_PCM_IOPLUG_HW_PERIODS); 362d5ac70f0Sopenharmony_ci if (err < 0) 363d5ac70f0Sopenharmony_ci return err; 364d5ac70f0Sopenharmony_ci change2 |= err; 365d5ac70f0Sopenharmony_ci /* buffer_bytes = periods * period_bytes */ 366d5ac70f0Sopenharmony_ci err = rule_mul(params, SND_PCM_HW_PARAM_BUFFER_BYTES, 367d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_BYTES, 368d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIODS); 369d5ac70f0Sopenharmony_ci if (err < 0) 370d5ac70f0Sopenharmony_ci return err; 371d5ac70f0Sopenharmony_ci change2 |= err; 372d5ac70f0Sopenharmony_ci change1 |= change2; 373d5ac70f0Sopenharmony_ci } while (change2); 374d5ac70f0Sopenharmony_ci change |= change1; 375d5ac70f0Sopenharmony_ci 376d5ac70f0Sopenharmony_ci if (change1) { 377d5ac70f0Sopenharmony_ci err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_BUFFER_TIME, 378d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_SIZE, 379d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_BYTES); 380d5ac70f0Sopenharmony_ci if (err < 0) 381d5ac70f0Sopenharmony_ci return err; 382d5ac70f0Sopenharmony_ci } 383d5ac70f0Sopenharmony_ci 384d5ac70f0Sopenharmony_ci /* period_bytes = buffer_bytes / periods */ 385d5ac70f0Sopenharmony_ci err = rule_div(params, SND_PCM_HW_PARAM_PERIOD_BYTES, 386d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_BYTES, 387d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIODS); 388d5ac70f0Sopenharmony_ci if (err < 0) 389d5ac70f0Sopenharmony_ci return err; 390d5ac70f0Sopenharmony_ci if (err) { 391d5ac70f0Sopenharmony_ci /* update period_size and period_time */ 392d5ac70f0Sopenharmony_ci change |= err; 393d5ac70f0Sopenharmony_ci err = snd_ext_parm_interval_refine(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_BYTES), 394d5ac70f0Sopenharmony_ci io->params, SND_PCM_IOPLUG_HW_PERIOD_BYTES); 395d5ac70f0Sopenharmony_ci if (err < 0) 396d5ac70f0Sopenharmony_ci return err; 397d5ac70f0Sopenharmony_ci err = refine_back_time_and_size(params, SND_PCM_HW_PARAM_PERIOD_TIME, 398d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_SIZE, 399d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_BYTES); 400d5ac70f0Sopenharmony_ci if (err < 0) 401d5ac70f0Sopenharmony_ci return err; 402d5ac70f0Sopenharmony_ci } 403d5ac70f0Sopenharmony_ci 404d5ac70f0Sopenharmony_ci params->info = SND_PCM_INFO_BLOCK_TRANSFER; 405d5ac70f0Sopenharmony_ci p = &io->params[SND_PCM_IOPLUG_HW_ACCESS]; 406d5ac70f0Sopenharmony_ci if (p->active) { 407d5ac70f0Sopenharmony_ci for (i = 0; i < p->num_list; i++) 408d5ac70f0Sopenharmony_ci switch (p->list[i]) { 409d5ac70f0Sopenharmony_ci case SND_PCM_ACCESS_MMAP_INTERLEAVED: 410d5ac70f0Sopenharmony_ci case SND_PCM_ACCESS_RW_INTERLEAVED: 411d5ac70f0Sopenharmony_ci params->info |= SND_PCM_INFO_INTERLEAVED; 412d5ac70f0Sopenharmony_ci break; 413d5ac70f0Sopenharmony_ci case SND_PCM_ACCESS_MMAP_NONINTERLEAVED: 414d5ac70f0Sopenharmony_ci case SND_PCM_ACCESS_RW_NONINTERLEAVED: 415d5ac70f0Sopenharmony_ci params->info |= SND_PCM_INFO_NONINTERLEAVED; 416d5ac70f0Sopenharmony_ci break; 417d5ac70f0Sopenharmony_ci } 418d5ac70f0Sopenharmony_ci } 419d5ac70f0Sopenharmony_ci if (io->data->callback->pause) 420d5ac70f0Sopenharmony_ci params->info |= SND_PCM_INFO_PAUSE; 421d5ac70f0Sopenharmony_ci if (io->data->callback->resume) 422d5ac70f0Sopenharmony_ci params->info |= SND_PCM_INFO_RESUME; 423d5ac70f0Sopenharmony_ci 424d5ac70f0Sopenharmony_ci#if 0 425d5ac70f0Sopenharmony_ci fprintf(stderr, "XXX\n"); 426d5ac70f0Sopenharmony_ci dump_parm(params); 427d5ac70f0Sopenharmony_ci#endif 428d5ac70f0Sopenharmony_ci return change; 429d5ac70f0Sopenharmony_ci} 430d5ac70f0Sopenharmony_ci 431d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 432d5ac70f0Sopenharmony_ci{ 433d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 434d5ac70f0Sopenharmony_ci int err; 435d5ac70f0Sopenharmony_ci 436d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access); 437d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format); 438d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels); 439d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0); 440d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0); 441d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size); 442d5ac70f0Sopenharmony_ci if (io->data->callback->hw_params) { 443d5ac70f0Sopenharmony_ci err = io->data->callback->hw_params(io->data, params); 444d5ac70f0Sopenharmony_ci if (err < 0) 445d5ac70f0Sopenharmony_ci return err; 446d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_access)(params, &io->data->access); 447d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_format)(params, &io->data->format); 448d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_channels)(params, &io->data->channels); 449d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_rate)(params, &io->data->rate, 0); 450d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_period_size)(params, &io->data->period_size, 0); 451d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_buffer_size)(params, &io->data->buffer_size); 452d5ac70f0Sopenharmony_ci } 453d5ac70f0Sopenharmony_ci return 0; 454d5ac70f0Sopenharmony_ci} 455d5ac70f0Sopenharmony_ci 456d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_hw_free(snd_pcm_t *pcm) 457d5ac70f0Sopenharmony_ci{ 458d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 459d5ac70f0Sopenharmony_ci 460d5ac70f0Sopenharmony_ci if (io->data->callback->hw_free) 461d5ac70f0Sopenharmony_ci return io->data->callback->hw_free(io->data); 462d5ac70f0Sopenharmony_ci return 0; 463d5ac70f0Sopenharmony_ci} 464d5ac70f0Sopenharmony_ci 465d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) 466d5ac70f0Sopenharmony_ci{ 467d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 468d5ac70f0Sopenharmony_ci int err; 469d5ac70f0Sopenharmony_ci 470d5ac70f0Sopenharmony_ci if (!io->data->callback->sw_params) 471d5ac70f0Sopenharmony_ci return 0; 472d5ac70f0Sopenharmony_ci 473d5ac70f0Sopenharmony_ci snd_pcm_unlock(pcm); /* to avoid deadlock */ 474d5ac70f0Sopenharmony_ci err = io->data->callback->sw_params(io->data, params); 475d5ac70f0Sopenharmony_ci snd_pcm_lock(pcm); 476d5ac70f0Sopenharmony_ci 477d5ac70f0Sopenharmony_ci return err; 478d5ac70f0Sopenharmony_ci} 479d5ac70f0Sopenharmony_ci 480d5ac70f0Sopenharmony_ci 481d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_start(snd_pcm_t *pcm) 482d5ac70f0Sopenharmony_ci{ 483d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 484d5ac70f0Sopenharmony_ci int err; 485d5ac70f0Sopenharmony_ci 486d5ac70f0Sopenharmony_ci if (io->data->state != SND_PCM_STATE_PREPARED) 487d5ac70f0Sopenharmony_ci return -EBADFD; 488d5ac70f0Sopenharmony_ci 489d5ac70f0Sopenharmony_ci err = io->data->callback->start(io->data); 490d5ac70f0Sopenharmony_ci if (err < 0) 491d5ac70f0Sopenharmony_ci return err; 492d5ac70f0Sopenharmony_ci 493d5ac70f0Sopenharmony_ci gettimestamp(&io->trigger_tstamp, pcm->tstamp_type); 494d5ac70f0Sopenharmony_ci io->data->state = SND_PCM_STATE_RUNNING; 495d5ac70f0Sopenharmony_ci 496d5ac70f0Sopenharmony_ci return 0; 497d5ac70f0Sopenharmony_ci} 498d5ac70f0Sopenharmony_ci 499d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_drop(snd_pcm_t *pcm) 500d5ac70f0Sopenharmony_ci{ 501d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 502d5ac70f0Sopenharmony_ci 503d5ac70f0Sopenharmony_ci if (io->data->state == SND_PCM_STATE_OPEN) 504d5ac70f0Sopenharmony_ci return -EBADFD; 505d5ac70f0Sopenharmony_ci 506d5ac70f0Sopenharmony_ci io->data->callback->stop(io->data); 507d5ac70f0Sopenharmony_ci 508d5ac70f0Sopenharmony_ci gettimestamp(&io->trigger_tstamp, pcm->tstamp_type); 509d5ac70f0Sopenharmony_ci io->data->state = SND_PCM_STATE_SETUP; 510d5ac70f0Sopenharmony_ci 511d5ac70f0Sopenharmony_ci return 0; 512d5ac70f0Sopenharmony_ci} 513d5ac70f0Sopenharmony_ci 514d5ac70f0Sopenharmony_cistatic int ioplug_drain_via_poll(snd_pcm_t *pcm) 515d5ac70f0Sopenharmony_ci{ 516d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 517d5ac70f0Sopenharmony_ci 518d5ac70f0Sopenharmony_ci while (io->data->state == SND_PCM_STATE_DRAINING) { 519d5ac70f0Sopenharmony_ci snd_pcm_ioplug_hw_ptr_update(pcm); 520d5ac70f0Sopenharmony_ci if (io->data->state != SND_PCM_STATE_DRAINING) 521d5ac70f0Sopenharmony_ci break; 522d5ac70f0Sopenharmony_ci /* in non-blocking mode, let application to poll() by itself */ 523d5ac70f0Sopenharmony_ci if (io->data->nonblock) 524d5ac70f0Sopenharmony_ci return -EAGAIN; 525d5ac70f0Sopenharmony_ci if (snd_pcm_wait_nocheck(pcm, SND_PCM_WAIT_DRAIN) < 0) 526d5ac70f0Sopenharmony_ci break; 527d5ac70f0Sopenharmony_ci } 528d5ac70f0Sopenharmony_ci 529d5ac70f0Sopenharmony_ci return 0; /* force to drop at error */ 530d5ac70f0Sopenharmony_ci} 531d5ac70f0Sopenharmony_ci 532d5ac70f0Sopenharmony_ci/* need own locking */ 533d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_drain(snd_pcm_t *pcm) 534d5ac70f0Sopenharmony_ci{ 535d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 536d5ac70f0Sopenharmony_ci int err = 0; 537d5ac70f0Sopenharmony_ci 538d5ac70f0Sopenharmony_ci snd_pcm_lock(pcm); 539d5ac70f0Sopenharmony_ci switch (io->data->state) { 540d5ac70f0Sopenharmony_ci case SND_PCM_STATE_OPEN: 541d5ac70f0Sopenharmony_ci case SND_PCM_STATE_DISCONNECTED: 542d5ac70f0Sopenharmony_ci case SND_PCM_STATE_SUSPENDED: 543d5ac70f0Sopenharmony_ci snd_pcm_unlock(pcm); 544d5ac70f0Sopenharmony_ci return -EBADFD; 545d5ac70f0Sopenharmony_ci case SND_PCM_STATE_PREPARED: 546d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 547d5ac70f0Sopenharmony_ci if (!io->data->callback->drain) { 548d5ac70f0Sopenharmony_ci err = snd_pcm_ioplug_start(pcm); 549d5ac70f0Sopenharmony_ci if (err < 0) 550d5ac70f0Sopenharmony_ci goto unlock; 551d5ac70f0Sopenharmony_ci } 552d5ac70f0Sopenharmony_ci io->data->state = SND_PCM_STATE_DRAINING; 553d5ac70f0Sopenharmony_ci } 554d5ac70f0Sopenharmony_ci break; 555d5ac70f0Sopenharmony_ci case SND_PCM_STATE_RUNNING: 556d5ac70f0Sopenharmony_ci io->data->state = SND_PCM_STATE_DRAINING; 557d5ac70f0Sopenharmony_ci break; 558d5ac70f0Sopenharmony_ci default: 559d5ac70f0Sopenharmony_ci break; 560d5ac70f0Sopenharmony_ci } 561d5ac70f0Sopenharmony_ci 562d5ac70f0Sopenharmony_ci if (io->data->state == SND_PCM_STATE_DRAINING) { 563d5ac70f0Sopenharmony_ci if (io->data->callback->drain) { 564d5ac70f0Sopenharmony_ci snd_pcm_unlock(pcm); /* let plugin own locking */ 565d5ac70f0Sopenharmony_ci err = io->data->callback->drain(io->data); 566d5ac70f0Sopenharmony_ci snd_pcm_lock(pcm); 567d5ac70f0Sopenharmony_ci } else { 568d5ac70f0Sopenharmony_ci err = ioplug_drain_via_poll(pcm); 569d5ac70f0Sopenharmony_ci } 570d5ac70f0Sopenharmony_ci } 571d5ac70f0Sopenharmony_ci 572d5ac70f0Sopenharmony_ci unlock: 573d5ac70f0Sopenharmony_ci if (!err && io->data->state != SND_PCM_STATE_SETUP) 574d5ac70f0Sopenharmony_ci snd_pcm_ioplug_drop(pcm); 575d5ac70f0Sopenharmony_ci snd_pcm_unlock(pcm); 576d5ac70f0Sopenharmony_ci return err; 577d5ac70f0Sopenharmony_ci} 578d5ac70f0Sopenharmony_ci 579d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_pause(snd_pcm_t *pcm, int enable) 580d5ac70f0Sopenharmony_ci{ 581d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 582d5ac70f0Sopenharmony_ci static const snd_pcm_state_t states[2] = { 583d5ac70f0Sopenharmony_ci SND_PCM_STATE_RUNNING, SND_PCM_STATE_PAUSED 584d5ac70f0Sopenharmony_ci }; 585d5ac70f0Sopenharmony_ci int prev, err; 586d5ac70f0Sopenharmony_ci 587d5ac70f0Sopenharmony_ci prev = !enable; 588d5ac70f0Sopenharmony_ci enable = !prev; 589d5ac70f0Sopenharmony_ci if (io->data->state != states[prev]) 590d5ac70f0Sopenharmony_ci return -EBADFD; 591d5ac70f0Sopenharmony_ci if (io->data->callback->pause) { 592d5ac70f0Sopenharmony_ci err = io->data->callback->pause(io->data, enable); 593d5ac70f0Sopenharmony_ci if (err < 0) 594d5ac70f0Sopenharmony_ci return err; 595d5ac70f0Sopenharmony_ci } 596d5ac70f0Sopenharmony_ci io->data->state = states[enable]; 597d5ac70f0Sopenharmony_ci return 0; 598d5ac70f0Sopenharmony_ci} 599d5ac70f0Sopenharmony_ci 600d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_rewindable(snd_pcm_t *pcm) 601d5ac70f0Sopenharmony_ci{ 602d5ac70f0Sopenharmony_ci return snd_pcm_mmap_hw_rewindable(pcm); 603d5ac70f0Sopenharmony_ci} 604d5ac70f0Sopenharmony_ci 605d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 606d5ac70f0Sopenharmony_ci{ 607d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_backward(pcm, frames); 608d5ac70f0Sopenharmony_ci return frames; 609d5ac70f0Sopenharmony_ci} 610d5ac70f0Sopenharmony_ci 611d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_forwardable(snd_pcm_t *pcm) 612d5ac70f0Sopenharmony_ci{ 613d5ac70f0Sopenharmony_ci return snd_pcm_mmap_avail(pcm); 614d5ac70f0Sopenharmony_ci} 615d5ac70f0Sopenharmony_ci 616d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 617d5ac70f0Sopenharmony_ci{ 618d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, frames); 619d5ac70f0Sopenharmony_ci return frames; 620d5ac70f0Sopenharmony_ci} 621d5ac70f0Sopenharmony_ci 622d5ac70f0Sopenharmony_ci/* need own locking */ 623d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_resume(snd_pcm_t *pcm) 624d5ac70f0Sopenharmony_ci{ 625d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 626d5ac70f0Sopenharmony_ci 627d5ac70f0Sopenharmony_ci if (io->data->callback->resume) 628d5ac70f0Sopenharmony_ci io->data->callback->resume(io->data); 629d5ac70f0Sopenharmony_ci return 0; 630d5ac70f0Sopenharmony_ci} 631d5ac70f0Sopenharmony_ci 632d5ac70f0Sopenharmony_ci/* called in lock */ 633d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t ioplug_priv_transfer_areas(snd_pcm_t *pcm, 634d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 635d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 636d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 637d5ac70f0Sopenharmony_ci{ 638d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 639d5ac70f0Sopenharmony_ci snd_pcm_sframes_t result; 640d5ac70f0Sopenharmony_ci 641d5ac70f0Sopenharmony_ci if (! size) 642d5ac70f0Sopenharmony_ci return 0; 643d5ac70f0Sopenharmony_ci if (io->data->callback->transfer) 644d5ac70f0Sopenharmony_ci result = io->data->callback->transfer(io->data, areas, offset, size); 645d5ac70f0Sopenharmony_ci else 646d5ac70f0Sopenharmony_ci result = size; 647d5ac70f0Sopenharmony_ci if (result > 0) 648d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, result); 649d5ac70f0Sopenharmony_ci return result; 650d5ac70f0Sopenharmony_ci} 651d5ac70f0Sopenharmony_ci 652d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) 653d5ac70f0Sopenharmony_ci{ 654d5ac70f0Sopenharmony_ci if (pcm->mmap_rw) 655d5ac70f0Sopenharmony_ci return snd_pcm_mmap_writei(pcm, buffer, size); 656d5ac70f0Sopenharmony_ci else { 657d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 658d5ac70f0Sopenharmony_ci snd_pcm_areas_from_buf(pcm, areas, (void*)buffer); 659d5ac70f0Sopenharmony_ci return snd_pcm_write_areas(pcm, areas, 0, size, 660d5ac70f0Sopenharmony_ci ioplug_priv_transfer_areas); 661d5ac70f0Sopenharmony_ci } 662d5ac70f0Sopenharmony_ci} 663d5ac70f0Sopenharmony_ci 664d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) 665d5ac70f0Sopenharmony_ci{ 666d5ac70f0Sopenharmony_ci if (pcm->mmap_rw) 667d5ac70f0Sopenharmony_ci return snd_pcm_mmap_writen(pcm, bufs, size); 668d5ac70f0Sopenharmony_ci else { 669d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 670d5ac70f0Sopenharmony_ci snd_pcm_areas_from_bufs(pcm, areas, bufs); 671d5ac70f0Sopenharmony_ci return snd_pcm_write_areas(pcm, areas, 0, size, 672d5ac70f0Sopenharmony_ci ioplug_priv_transfer_areas); 673d5ac70f0Sopenharmony_ci } 674d5ac70f0Sopenharmony_ci} 675d5ac70f0Sopenharmony_ci 676d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) 677d5ac70f0Sopenharmony_ci{ 678d5ac70f0Sopenharmony_ci if (pcm->mmap_rw) 679d5ac70f0Sopenharmony_ci return snd_pcm_mmap_readi(pcm, buffer, size); 680d5ac70f0Sopenharmony_ci else { 681d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 682d5ac70f0Sopenharmony_ci snd_pcm_areas_from_buf(pcm, areas, buffer); 683d5ac70f0Sopenharmony_ci return snd_pcm_read_areas(pcm, areas, 0, size, 684d5ac70f0Sopenharmony_ci ioplug_priv_transfer_areas); 685d5ac70f0Sopenharmony_ci } 686d5ac70f0Sopenharmony_ci} 687d5ac70f0Sopenharmony_ci 688d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) 689d5ac70f0Sopenharmony_ci{ 690d5ac70f0Sopenharmony_ci if (pcm->mmap_rw) 691d5ac70f0Sopenharmony_ci return snd_pcm_mmap_readn(pcm, bufs, size); 692d5ac70f0Sopenharmony_ci else { 693d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 694d5ac70f0Sopenharmony_ci snd_pcm_areas_from_bufs(pcm, areas, bufs); 695d5ac70f0Sopenharmony_ci return snd_pcm_read_areas(pcm, areas, 0, size, 696d5ac70f0Sopenharmony_ci ioplug_priv_transfer_areas); 697d5ac70f0Sopenharmony_ci } 698d5ac70f0Sopenharmony_ci} 699d5ac70f0Sopenharmony_ci 700d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_mmap_begin_capture(snd_pcm_t *pcm, 701d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t **areas, 702d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *offset, 703d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *frames) 704d5ac70f0Sopenharmony_ci{ 705d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 706d5ac70f0Sopenharmony_ci int err; 707d5ac70f0Sopenharmony_ci 708d5ac70f0Sopenharmony_ci err = __snd_pcm_mmap_begin_generic(pcm, areas, offset, frames); 709d5ac70f0Sopenharmony_ci if (err < 0) 710d5ac70f0Sopenharmony_ci return err; 711d5ac70f0Sopenharmony_ci 712d5ac70f0Sopenharmony_ci if (io->data->callback->transfer && 713d5ac70f0Sopenharmony_ci pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && 714d5ac70f0Sopenharmony_ci pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { 715d5ac70f0Sopenharmony_ci snd_pcm_sframes_t result; 716d5ac70f0Sopenharmony_ci result = io->data->callback->transfer(io->data, *areas, *offset, *frames); 717d5ac70f0Sopenharmony_ci if (result < 0) 718d5ac70f0Sopenharmony_ci return result; 719d5ac70f0Sopenharmony_ci } 720d5ac70f0Sopenharmony_ci 721d5ac70f0Sopenharmony_ci return err; 722d5ac70f0Sopenharmony_ci} 723d5ac70f0Sopenharmony_ci 724d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_mmap_begin(snd_pcm_t *pcm, const snd_pcm_channel_area_t **areas, 725d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *offset, snd_pcm_uframes_t *frames) 726d5ac70f0Sopenharmony_ci{ 727d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) 728d5ac70f0Sopenharmony_ci return __snd_pcm_mmap_begin_generic(pcm, areas, offset, frames); 729d5ac70f0Sopenharmony_ci return snd_pcm_ioplug_mmap_begin_capture(pcm, areas, offset, frames); 730d5ac70f0Sopenharmony_ci} 731d5ac70f0Sopenharmony_ci 732d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_mmap_commit(snd_pcm_t *pcm, 733d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 734d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 735d5ac70f0Sopenharmony_ci{ 736d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK && 737d5ac70f0Sopenharmony_ci pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && 738d5ac70f0Sopenharmony_ci pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { 739d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas; 740d5ac70f0Sopenharmony_ci snd_pcm_uframes_t ofs, frames = size; 741d5ac70f0Sopenharmony_ci 742d5ac70f0Sopenharmony_ci __snd_pcm_mmap_begin_generic(pcm, &areas, &ofs, &frames); 743d5ac70f0Sopenharmony_ci if (ofs != offset) 744d5ac70f0Sopenharmony_ci return -EIO; 745d5ac70f0Sopenharmony_ci return ioplug_priv_transfer_areas(pcm, areas, offset, frames); 746d5ac70f0Sopenharmony_ci } 747d5ac70f0Sopenharmony_ci 748d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, size); 749d5ac70f0Sopenharmony_ci return size; 750d5ac70f0Sopenharmony_ci} 751d5ac70f0Sopenharmony_ci 752d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_ioplug_avail_update(snd_pcm_t *pcm) 753d5ac70f0Sopenharmony_ci{ 754d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 755d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail; 756d5ac70f0Sopenharmony_ci 757d5ac70f0Sopenharmony_ci snd_pcm_ioplug_hw_ptr_update(pcm); 758d5ac70f0Sopenharmony_ci if (io->data->state == SND_PCM_STATE_XRUN) 759d5ac70f0Sopenharmony_ci return -EPIPE; 760d5ac70f0Sopenharmony_ci 761d5ac70f0Sopenharmony_ci avail = snd_pcm_mmap_avail(pcm); 762d5ac70f0Sopenharmony_ci if (avail > io->avail_max) 763d5ac70f0Sopenharmony_ci io->avail_max = avail; 764d5ac70f0Sopenharmony_ci return (snd_pcm_sframes_t)avail; 765d5ac70f0Sopenharmony_ci} 766d5ac70f0Sopenharmony_ci 767d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_nonblock(snd_pcm_t *pcm, int nonblock) 768d5ac70f0Sopenharmony_ci{ 769d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 770d5ac70f0Sopenharmony_ci 771d5ac70f0Sopenharmony_ci io->data->nonblock = nonblock; 772d5ac70f0Sopenharmony_ci return 0; 773d5ac70f0Sopenharmony_ci} 774d5ac70f0Sopenharmony_ci 775d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_descriptors_count(snd_pcm_t *pcm) 776d5ac70f0Sopenharmony_ci{ 777d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 778d5ac70f0Sopenharmony_ci int err = 1; 779d5ac70f0Sopenharmony_ci 780d5ac70f0Sopenharmony_ci if (io->data->callback->poll_descriptors_count) { 781d5ac70f0Sopenharmony_ci snd_pcm_unlock(pcm); /* to avoid deadlock */ 782d5ac70f0Sopenharmony_ci err = io->data->callback->poll_descriptors_count(io->data); 783d5ac70f0Sopenharmony_ci snd_pcm_lock(pcm); 784d5ac70f0Sopenharmony_ci } 785d5ac70f0Sopenharmony_ci return err; 786d5ac70f0Sopenharmony_ci} 787d5ac70f0Sopenharmony_ci 788d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int space) 789d5ac70f0Sopenharmony_ci{ 790d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 791d5ac70f0Sopenharmony_ci int err; 792d5ac70f0Sopenharmony_ci 793d5ac70f0Sopenharmony_ci if (io->data->callback->poll_descriptors) { 794d5ac70f0Sopenharmony_ci snd_pcm_unlock(pcm); /* to avoid deadlock */ 795d5ac70f0Sopenharmony_ci err = io->data->callback->poll_descriptors(io->data, pfds, space); 796d5ac70f0Sopenharmony_ci snd_pcm_lock(pcm); 797d5ac70f0Sopenharmony_ci return err; 798d5ac70f0Sopenharmony_ci } 799d5ac70f0Sopenharmony_ci if (pcm->poll_fd < 0) 800d5ac70f0Sopenharmony_ci return -EIO; 801d5ac70f0Sopenharmony_ci if (space >= 1 && pfds) { 802d5ac70f0Sopenharmony_ci pfds->fd = pcm->poll_fd; 803d5ac70f0Sopenharmony_ci pfds->events = pcm->poll_events | POLLERR | POLLNVAL; 804d5ac70f0Sopenharmony_ci } else { 805d5ac70f0Sopenharmony_ci return 0; 806d5ac70f0Sopenharmony_ci } 807d5ac70f0Sopenharmony_ci return 1; 808d5ac70f0Sopenharmony_ci} 809d5ac70f0Sopenharmony_ci 810d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) 811d5ac70f0Sopenharmony_ci{ 812d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 813d5ac70f0Sopenharmony_ci int err; 814d5ac70f0Sopenharmony_ci 815d5ac70f0Sopenharmony_ci if (io->data->callback->poll_revents) { 816d5ac70f0Sopenharmony_ci snd_pcm_unlock(pcm); /* to avoid deadlock */ 817d5ac70f0Sopenharmony_ci err = io->data->callback->poll_revents(io->data, pfds, nfds, revents); 818d5ac70f0Sopenharmony_ci snd_pcm_lock(pcm); 819d5ac70f0Sopenharmony_ci } else { 820d5ac70f0Sopenharmony_ci *revents = pfds->revents; 821d5ac70f0Sopenharmony_ci err = 0; 822d5ac70f0Sopenharmony_ci } 823d5ac70f0Sopenharmony_ci return err; 824d5ac70f0Sopenharmony_ci} 825d5ac70f0Sopenharmony_ci 826d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 827d5ac70f0Sopenharmony_ci{ 828d5ac70f0Sopenharmony_ci return 0; 829d5ac70f0Sopenharmony_ci} 830d5ac70f0Sopenharmony_ci 831d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, 832d5ac70f0Sopenharmony_ci int sig ATTRIBUTE_UNUSED, 833d5ac70f0Sopenharmony_ci pid_t pid ATTRIBUTE_UNUSED) 834d5ac70f0Sopenharmony_ci{ 835d5ac70f0Sopenharmony_ci return -ENOSYS; 836d5ac70f0Sopenharmony_ci} 837d5ac70f0Sopenharmony_ci 838d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 839d5ac70f0Sopenharmony_ci{ 840d5ac70f0Sopenharmony_ci return 0; 841d5ac70f0Sopenharmony_ci} 842d5ac70f0Sopenharmony_ci 843d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_query_t **snd_pcm_ioplug_query_chmaps(snd_pcm_t *pcm) 844d5ac70f0Sopenharmony_ci{ 845d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 846d5ac70f0Sopenharmony_ci 847d5ac70f0Sopenharmony_ci if (io->data->version >= 0x010002 && 848d5ac70f0Sopenharmony_ci io->data->callback->query_chmaps) 849d5ac70f0Sopenharmony_ci return io->data->callback->query_chmaps(io->data); 850d5ac70f0Sopenharmony_ci return NULL; 851d5ac70f0Sopenharmony_ci} 852d5ac70f0Sopenharmony_ci 853d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_t *snd_pcm_ioplug_get_chmap(snd_pcm_t *pcm) 854d5ac70f0Sopenharmony_ci{ 855d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 856d5ac70f0Sopenharmony_ci 857d5ac70f0Sopenharmony_ci if (io->data->version >= 0x010002 && 858d5ac70f0Sopenharmony_ci io->data->callback->get_chmap) 859d5ac70f0Sopenharmony_ci return io->data->callback->get_chmap(io->data); 860d5ac70f0Sopenharmony_ci return NULL; 861d5ac70f0Sopenharmony_ci} 862d5ac70f0Sopenharmony_ci 863d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) 864d5ac70f0Sopenharmony_ci{ 865d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 866d5ac70f0Sopenharmony_ci 867d5ac70f0Sopenharmony_ci if (io->data->version >= 0x010002 && 868d5ac70f0Sopenharmony_ci io->data->callback->set_chmap) 869d5ac70f0Sopenharmony_ci return io->data->callback->set_chmap(io->data, map); 870d5ac70f0Sopenharmony_ci return -ENXIO; 871d5ac70f0Sopenharmony_ci} 872d5ac70f0Sopenharmony_ci 873d5ac70f0Sopenharmony_cistatic void snd_pcm_ioplug_dump(snd_pcm_t *pcm, snd_output_t *out) 874d5ac70f0Sopenharmony_ci{ 875d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 876d5ac70f0Sopenharmony_ci 877d5ac70f0Sopenharmony_ci if (io->data->callback->dump) 878d5ac70f0Sopenharmony_ci io->data->callback->dump(io->data, out); 879d5ac70f0Sopenharmony_ci else { 880d5ac70f0Sopenharmony_ci if (io->data->name) 881d5ac70f0Sopenharmony_ci snd_output_printf(out, "%s\n", io->data->name); 882d5ac70f0Sopenharmony_ci else 883d5ac70f0Sopenharmony_ci snd_output_printf(out, "IO-PCM Plugin\n"); 884d5ac70f0Sopenharmony_ci if (pcm->setup) { 885d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 886d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 887d5ac70f0Sopenharmony_ci } 888d5ac70f0Sopenharmony_ci } 889d5ac70f0Sopenharmony_ci} 890d5ac70f0Sopenharmony_ci 891d5ac70f0Sopenharmony_cistatic void clear_io_params(ioplug_priv_t *io) 892d5ac70f0Sopenharmony_ci{ 893d5ac70f0Sopenharmony_ci int i; 894d5ac70f0Sopenharmony_ci for (i = 0; i < SND_PCM_IOPLUG_HW_PARAMS; i++) 895d5ac70f0Sopenharmony_ci snd_ext_parm_clear(&io->params[i]); 896d5ac70f0Sopenharmony_ci} 897d5ac70f0Sopenharmony_ci 898d5ac70f0Sopenharmony_cistatic int snd_pcm_ioplug_close(snd_pcm_t *pcm) 899d5ac70f0Sopenharmony_ci{ 900d5ac70f0Sopenharmony_ci ioplug_priv_t *io = pcm->private_data; 901d5ac70f0Sopenharmony_ci 902d5ac70f0Sopenharmony_ci clear_io_params(io); 903d5ac70f0Sopenharmony_ci if (io->data->callback->close) 904d5ac70f0Sopenharmony_ci io->data->callback->close(io->data); 905d5ac70f0Sopenharmony_ci free(io); 906d5ac70f0Sopenharmony_ci 907d5ac70f0Sopenharmony_ci return 0; 908d5ac70f0Sopenharmony_ci} 909d5ac70f0Sopenharmony_ci 910d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_ioplug_ops = { 911d5ac70f0Sopenharmony_ci .close = snd_pcm_ioplug_close, 912d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_ioplug_nonblock, 913d5ac70f0Sopenharmony_ci .async = snd_pcm_ioplug_async, 914d5ac70f0Sopenharmony_ci .info = snd_pcm_ioplug_info, 915d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_ioplug_hw_refine, 916d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_ioplug_hw_params, 917d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_ioplug_hw_free, 918d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_ioplug_sw_params, 919d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_ioplug_channel_info, 920d5ac70f0Sopenharmony_ci .dump = snd_pcm_ioplug_dump, 921d5ac70f0Sopenharmony_ci .mmap = snd_pcm_ioplug_mmap, 922d5ac70f0Sopenharmony_ci .munmap = snd_pcm_ioplug_munmap, 923d5ac70f0Sopenharmony_ci .query_chmaps = snd_pcm_ioplug_query_chmaps, 924d5ac70f0Sopenharmony_ci .get_chmap = snd_pcm_ioplug_get_chmap, 925d5ac70f0Sopenharmony_ci .set_chmap = snd_pcm_ioplug_set_chmap, 926d5ac70f0Sopenharmony_ci}; 927d5ac70f0Sopenharmony_ci 928d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = { 929d5ac70f0Sopenharmony_ci .status = snd_pcm_ioplug_status, 930d5ac70f0Sopenharmony_ci .prepare = snd_pcm_ioplug_prepare, 931d5ac70f0Sopenharmony_ci .reset = snd_pcm_ioplug_reset, 932d5ac70f0Sopenharmony_ci .start = snd_pcm_ioplug_start, 933d5ac70f0Sopenharmony_ci .drop = snd_pcm_ioplug_drop, 934d5ac70f0Sopenharmony_ci .drain = snd_pcm_ioplug_drain, 935d5ac70f0Sopenharmony_ci .pause = snd_pcm_ioplug_pause, 936d5ac70f0Sopenharmony_ci .state = snd_pcm_ioplug_state, 937d5ac70f0Sopenharmony_ci .hwsync = snd_pcm_ioplug_hwsync, 938d5ac70f0Sopenharmony_ci .delay = snd_pcm_ioplug_delay, 939d5ac70f0Sopenharmony_ci .resume = snd_pcm_ioplug_resume, 940d5ac70f0Sopenharmony_ci .link = NULL, 941d5ac70f0Sopenharmony_ci .link_slaves = NULL, 942d5ac70f0Sopenharmony_ci .unlink = NULL, 943d5ac70f0Sopenharmony_ci .rewindable = snd_pcm_ioplug_rewindable, 944d5ac70f0Sopenharmony_ci .rewind = snd_pcm_ioplug_rewind, 945d5ac70f0Sopenharmony_ci .forwardable = snd_pcm_ioplug_forwardable, 946d5ac70f0Sopenharmony_ci .forward = snd_pcm_ioplug_forward, 947d5ac70f0Sopenharmony_ci .writei = snd_pcm_ioplug_writei, 948d5ac70f0Sopenharmony_ci .writen = snd_pcm_ioplug_writen, 949d5ac70f0Sopenharmony_ci .readi = snd_pcm_ioplug_readi, 950d5ac70f0Sopenharmony_ci .readn = snd_pcm_ioplug_readn, 951d5ac70f0Sopenharmony_ci .avail_update = snd_pcm_ioplug_avail_update, 952d5ac70f0Sopenharmony_ci .mmap_commit = snd_pcm_ioplug_mmap_commit, 953d5ac70f0Sopenharmony_ci .htimestamp = snd_pcm_generic_real_htimestamp, 954d5ac70f0Sopenharmony_ci .poll_descriptors_count = snd_pcm_ioplug_poll_descriptors_count, 955d5ac70f0Sopenharmony_ci .poll_descriptors = snd_pcm_ioplug_poll_descriptors, 956d5ac70f0Sopenharmony_ci .poll_revents = snd_pcm_ioplug_poll_revents, 957d5ac70f0Sopenharmony_ci .mmap_begin = snd_pcm_ioplug_mmap_begin, 958d5ac70f0Sopenharmony_ci}; 959d5ac70f0Sopenharmony_ci 960d5ac70f0Sopenharmony_ci#endif /* !DOC_HIDDEN */ 961d5ac70f0Sopenharmony_ci 962d5ac70f0Sopenharmony_ci/* 963d5ac70f0Sopenharmony_ci * Exported functions 964d5ac70f0Sopenharmony_ci */ 965d5ac70f0Sopenharmony_ci 966d5ac70f0Sopenharmony_ci/*! \page pcm_external_plugins PCM External Plugin SDK 967d5ac70f0Sopenharmony_ci 968d5ac70f0Sopenharmony_ci\section pcm_ioplug External Plugin: I/O Plugin 969d5ac70f0Sopenharmony_ci 970d5ac70f0Sopenharmony_ciThe I/O-type plugin is a PCM plugin to work as the input or output terminal point, 971d5ac70f0Sopenharmony_cii.e. as a user-space PCM driver. 972d5ac70f0Sopenharmony_ci 973d5ac70f0Sopenharmony_ciThe new plugin is created via #snd_pcm_ioplug_create() function. 974d5ac70f0Sopenharmony_ciThe first argument is a pointer of the pluging information. Some of 975d5ac70f0Sopenharmony_cithis struct must be initialized in prior to call 976d5ac70f0Sopenharmony_ci#snd_pcm_ioplug_create(). Then the function fills other fields in 977d5ac70f0Sopenharmony_cireturn. The rest arguments, name, stream and mode, are usually 978d5ac70f0Sopenharmony_ciidentical with the values passed from the ALSA plugin constructor. 979d5ac70f0Sopenharmony_ci 980d5ac70f0Sopenharmony_ciThe following fields are mandatory: version, name, callback. 981d5ac70f0Sopenharmony_ciOtherfields are optional and should be initialized with zero. 982d5ac70f0Sopenharmony_ci 983d5ac70f0Sopenharmony_ciThe constant #SND_PCM_IOPLUG_VERSION must be passed to the version 984d5ac70f0Sopenharmony_cifield for the version check in alsa-lib. A non-NULL ASCII string 985d5ac70f0Sopenharmony_cihas to be passed to the name field. The callback field contains the 986d5ac70f0Sopenharmony_citable of callback functions for this plugin (defined as 987d5ac70f0Sopenharmony_ci#snd_pcm_ioplug_callback_t). 988d5ac70f0Sopenharmony_ci 989d5ac70f0Sopenharmony_ciflags field specifies the optional bit-flags. poll_fd and poll_events 990d5ac70f0Sopenharmony_cispecify the poll file descriptor and the corresponding poll events 991d5ac70f0Sopenharmony_ci(POLLIN, POLLOUT) for the plugin. If the plugin requires multiple 992d5ac70f0Sopenharmony_cipoll descriptors or poll descriptor(s) dynamically varying, set 993d5ac70f0Sopenharmony_cipoll_descriptors and poll_descriptors_count callbacks to the callback 994d5ac70f0Sopenharmony_citable. Then the poll_fd and poll_events field are ignored. 995d5ac70f0Sopenharmony_ci 996d5ac70f0Sopenharmony_cimmap_rw specifies whether the plugin behaves in the pseudo mmap mode. 997d5ac70f0Sopenharmony_ciWhen this value is set to 1, the plugin creates always a local buffer 998d5ac70f0Sopenharmony_ciand performs read/write calls using this buffer as if it's mmapped. 999d5ac70f0Sopenharmony_ciThe address of local buffer can be obtained via 1000d5ac70f0Sopenharmony_ci#snd_pcm_ioplug_mmap_areas() function. 1001d5ac70f0Sopenharmony_ciWhen poll_fd, poll_events and mmap_rw fields are changed after 1002d5ac70f0Sopenharmony_ci#snd_pcm_ioplug_create(), call #snd_pcm_ioplug_reinit_status() to 1003d5ac70f0Sopenharmony_cireflect the changes. 1004d5ac70f0Sopenharmony_ci 1005d5ac70f0Sopenharmony_ciThe driver can set an arbitrary value (pointer) to private_data 1006d5ac70f0Sopenharmony_cifield to refer its own data in the callbacks. 1007d5ac70f0Sopenharmony_ci 1008d5ac70f0Sopenharmony_ciThe rest fields are filled by #snd_pcm_ioplug_create(). The pcm field 1009d5ac70f0Sopenharmony_ciis the resultant PCM handle. The others are the current status of the 1010d5ac70f0Sopenharmony_ciPCM. 1011d5ac70f0Sopenharmony_ci 1012d5ac70f0Sopenharmony_ciThe callback functions in #snd_pcm_ioplug_callback_t define the real 1013d5ac70f0Sopenharmony_cibehavior of the driver. 1014d5ac70f0Sopenharmony_ciAt least, start, stop and pointer callbacks must be given. Other 1015d5ac70f0Sopenharmony_cicallbacks are optional. The start and stop callbacks are called when 1016d5ac70f0Sopenharmony_cithe PCM stream is started and stopped, repsectively. The pointer 1017d5ac70f0Sopenharmony_cicallback returns the current DMA position, which may be called at any 1018d5ac70f0Sopenharmony_citime. 1019d5ac70f0Sopenharmony_ci 1020d5ac70f0Sopenharmony_ciThe transfer callback is called when any data transfer happens. It 1021d5ac70f0Sopenharmony_cireceives the area array, offset and the size to transfer. The area 1022d5ac70f0Sopenharmony_ciarray contains the array of snd_pcm_channel_area_t with the elements 1023d5ac70f0Sopenharmony_ciof number of channels. 1024d5ac70f0Sopenharmony_ci 1025d5ac70f0Sopenharmony_ciWhen the PCM is closed, close callback is called. If the driver 1026d5ac70f0Sopenharmony_ciallocates any internal buffers, they should be released in this 1027d5ac70f0Sopenharmony_cicallback. The hw_params and hw_free callbacks are called when 1028d5ac70f0Sopenharmony_cihw_params are set and reset, respectively. Note that they may be 1029d5ac70f0Sopenharmony_cicalled multiple times according to the application. Similarly, 1030d5ac70f0Sopenharmony_cisw_params callback is called when sw_params is set or changed. 1031d5ac70f0Sopenharmony_ci 1032d5ac70f0Sopenharmony_ciThe prepare, drain, pause and resume callbacks are called when 1033d5ac70f0Sopenharmony_ci#snd_pcm_prepare(), #snd_pcm_drain(), #snd_pcm_pause(), and 1034d5ac70f0Sopenharmony_ci#snd_pcm_resume() are called. The poll_descriptors_count and 1035d5ac70f0Sopenharmony_cipoll_descriptors callbacks are used to return the multiple or dynamic 1036d5ac70f0Sopenharmony_cipoll descriptors as mentioned above. The poll_revents callback is 1037d5ac70f0Sopenharmony_ciused to modify poll events. If the driver needs to mangle the native 1038d5ac70f0Sopenharmony_cipoll events to proper poll events for PCM, you can do it in this 1039d5ac70f0Sopenharmony_cicallback. 1040d5ac70f0Sopenharmony_ci 1041d5ac70f0Sopenharmony_ciFinally, the dump callback is used to print the status of the plugin. 1042d5ac70f0Sopenharmony_ci 1043d5ac70f0Sopenharmony_ciNote that some callbacks (start, stop, pointer, transfer and pause) 1044d5ac70f0Sopenharmony_cimay be called inside the internal pthread mutex, and they shouldn't 1045d5ac70f0Sopenharmony_cicall the PCM functions again unnecessarily from the callback itself; 1046d5ac70f0Sopenharmony_ciotherwise it may lead to a deadlock. 1047d5ac70f0Sopenharmony_ci 1048d5ac70f0Sopenharmony_ciThe hw_params constraints can be defined via either 1049d5ac70f0Sopenharmony_ci#snd_pcm_ioplug_set_param_minmax() and #snd_pcm_ioplug_set_param_list() 1050d5ac70f0Sopenharmony_cifunctions after calling #snd_pcm_ioplug_create(). 1051d5ac70f0Sopenharmony_ciThe former defines the minimal and maximal acceptable values for the 1052d5ac70f0Sopenharmony_cigiven hw_params parameter (SND_PCM_IOPLUG_HW_XXX). 1053d5ac70f0Sopenharmony_ciThis function can't be used for the format parameter. The latter 1054d5ac70f0Sopenharmony_cifunction specifies the available parameter values as the list. 1055d5ac70f0Sopenharmony_ci 1056d5ac70f0Sopenharmony_ciTo clear the parameter constraints, call #snd_pcm_ioplug_params_reset() function. 1057d5ac70f0Sopenharmony_ci 1058d5ac70f0Sopenharmony_ci*/ 1059d5ac70f0Sopenharmony_ci 1060d5ac70f0Sopenharmony_ci/** 1061d5ac70f0Sopenharmony_ci * \brief Create an ioplug instance 1062d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle 1063d5ac70f0Sopenharmony_ci * \param name name of PCM 1064d5ac70f0Sopenharmony_ci * \param stream stream direction 1065d5ac70f0Sopenharmony_ci * \param mode PCM open mode 1066d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 1067d5ac70f0Sopenharmony_ci * 1068d5ac70f0Sopenharmony_ci * Creates the ioplug instance. 1069d5ac70f0Sopenharmony_ci * 1070d5ac70f0Sopenharmony_ci * The callback is the mandatory field of ioplug handle. At least, start, stop and 1071d5ac70f0Sopenharmony_ci * pointer callbacks must be set before calling this function. 1072d5ac70f0Sopenharmony_ci * 1073d5ac70f0Sopenharmony_ci */ 1074d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_create(snd_pcm_ioplug_t *ioplug, const char *name, 1075d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 1076d5ac70f0Sopenharmony_ci{ 1077d5ac70f0Sopenharmony_ci ioplug_priv_t *io; 1078d5ac70f0Sopenharmony_ci int err; 1079d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 1080d5ac70f0Sopenharmony_ci 1081d5ac70f0Sopenharmony_ci assert(ioplug && ioplug->callback); 1082d5ac70f0Sopenharmony_ci assert(ioplug->callback->start && 1083d5ac70f0Sopenharmony_ci ioplug->callback->stop && 1084d5ac70f0Sopenharmony_ci ioplug->callback->pointer); 1085d5ac70f0Sopenharmony_ci 1086d5ac70f0Sopenharmony_ci /* We support 1.0.0 to current */ 1087d5ac70f0Sopenharmony_ci if (ioplug->version < 0x010000 || 1088d5ac70f0Sopenharmony_ci ioplug->version > SND_PCM_IOPLUG_VERSION) { 1089d5ac70f0Sopenharmony_ci SNDERR("ioplug: Plugin version mismatch: 0x%x", 1090d5ac70f0Sopenharmony_ci ioplug->version); 1091d5ac70f0Sopenharmony_ci return -ENXIO; 1092d5ac70f0Sopenharmony_ci } 1093d5ac70f0Sopenharmony_ci 1094d5ac70f0Sopenharmony_ci io = calloc(1, sizeof(*io)); 1095d5ac70f0Sopenharmony_ci if (! io) 1096d5ac70f0Sopenharmony_ci return -ENOMEM; 1097d5ac70f0Sopenharmony_ci 1098d5ac70f0Sopenharmony_ci io->data = ioplug; 1099d5ac70f0Sopenharmony_ci ioplug->state = SND_PCM_STATE_OPEN; 1100d5ac70f0Sopenharmony_ci ioplug->stream = stream; 1101d5ac70f0Sopenharmony_ci 1102d5ac70f0Sopenharmony_ci err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode); 1103d5ac70f0Sopenharmony_ci if (err < 0) { 1104d5ac70f0Sopenharmony_ci free(io); 1105d5ac70f0Sopenharmony_ci return err; 1106d5ac70f0Sopenharmony_ci } 1107d5ac70f0Sopenharmony_ci 1108d5ac70f0Sopenharmony_ci ioplug->pcm = pcm; 1109d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_ioplug_ops; 1110d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_ioplug_fast_ops; 1111d5ac70f0Sopenharmony_ci pcm->private_data = io; 1112d5ac70f0Sopenharmony_ci 1113d5ac70f0Sopenharmony_ci snd_pcm_set_hw_ptr(pcm, &ioplug->hw_ptr, -1, 0); 1114d5ac70f0Sopenharmony_ci snd_pcm_set_appl_ptr(pcm, &ioplug->appl_ptr, -1, 0); 1115d5ac70f0Sopenharmony_ci 1116d5ac70f0Sopenharmony_ci snd_pcm_ioplug_reinit_status(ioplug); 1117d5ac70f0Sopenharmony_ci 1118d5ac70f0Sopenharmony_ci return 0; 1119d5ac70f0Sopenharmony_ci} 1120d5ac70f0Sopenharmony_ci 1121d5ac70f0Sopenharmony_ci/** 1122d5ac70f0Sopenharmony_ci * \brief Delete the ioplug instance 1123d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle 1124d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 1125d5ac70f0Sopenharmony_ci */ 1126d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_delete(snd_pcm_ioplug_t *ioplug) 1127d5ac70f0Sopenharmony_ci{ 1128d5ac70f0Sopenharmony_ci return snd_pcm_close(ioplug->pcm); 1129d5ac70f0Sopenharmony_ci} 1130d5ac70f0Sopenharmony_ci 1131d5ac70f0Sopenharmony_ci 1132d5ac70f0Sopenharmony_ci/** 1133d5ac70f0Sopenharmony_ci * \brief Reset ioplug parameters 1134d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle 1135d5ac70f0Sopenharmony_ci * 1136d5ac70f0Sopenharmony_ci * Resets the all parameters for the given ioplug handle. 1137d5ac70f0Sopenharmony_ci */ 1138d5ac70f0Sopenharmony_civoid snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *ioplug) 1139d5ac70f0Sopenharmony_ci{ 1140d5ac70f0Sopenharmony_ci ioplug_priv_t *io = ioplug->pcm->private_data; 1141d5ac70f0Sopenharmony_ci clear_io_params(io); 1142d5ac70f0Sopenharmony_ci} 1143d5ac70f0Sopenharmony_ci 1144d5ac70f0Sopenharmony_ci/** 1145d5ac70f0Sopenharmony_ci * \brief Set parameter as the list 1146d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle 1147d5ac70f0Sopenharmony_ci * \param type parameter type 1148d5ac70f0Sopenharmony_ci * \param num_list number of available values 1149d5ac70f0Sopenharmony_ci * \param list the list of available values 1150d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 1151d5ac70f0Sopenharmony_ci * 1152d5ac70f0Sopenharmony_ci * Sets the parameter as the list. 1153d5ac70f0Sopenharmony_ci * The available values of the given parameter type is restricted to the ones of the given list. 1154d5ac70f0Sopenharmony_ci */ 1155d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *ioplug, int type, unsigned int num_list, const unsigned int *list) 1156d5ac70f0Sopenharmony_ci{ 1157d5ac70f0Sopenharmony_ci ioplug_priv_t *io = ioplug->pcm->private_data; 1158d5ac70f0Sopenharmony_ci if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) { 1159d5ac70f0Sopenharmony_ci SNDERR("IOPLUG: invalid parameter type %d", type); 1160d5ac70f0Sopenharmony_ci return -EINVAL; 1161d5ac70f0Sopenharmony_ci } 1162d5ac70f0Sopenharmony_ci if (type == SND_PCM_IOPLUG_HW_PERIODS) 1163d5ac70f0Sopenharmony_ci io->params[type].integer = 1; 1164d5ac70f0Sopenharmony_ci return snd_ext_parm_set_list(&io->params[type], num_list, list); 1165d5ac70f0Sopenharmony_ci} 1166d5ac70f0Sopenharmony_ci 1167d5ac70f0Sopenharmony_ci/** 1168d5ac70f0Sopenharmony_ci * \brief Set parameter as the min/max values 1169d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle 1170d5ac70f0Sopenharmony_ci * \param type parameter type 1171d5ac70f0Sopenharmony_ci * \param min the minimum value 1172d5ac70f0Sopenharmony_ci * \param max the maximum value 1173d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 1174d5ac70f0Sopenharmony_ci * 1175d5ac70f0Sopenharmony_ci * Sets the parameter as the min/max values. 1176d5ac70f0Sopenharmony_ci * The available values of the given parameter type is restricted between the given 1177d5ac70f0Sopenharmony_ci * minimum and maximum values. 1178d5ac70f0Sopenharmony_ci */ 1179d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *ioplug, int type, unsigned int min, unsigned int max) 1180d5ac70f0Sopenharmony_ci{ 1181d5ac70f0Sopenharmony_ci ioplug_priv_t *io = ioplug->pcm->private_data; 1182d5ac70f0Sopenharmony_ci if (type < 0 || type >= SND_PCM_IOPLUG_HW_PARAMS) { 1183d5ac70f0Sopenharmony_ci SNDERR("IOPLUG: invalid parameter type %d", type); 1184d5ac70f0Sopenharmony_ci return -EINVAL; 1185d5ac70f0Sopenharmony_ci } 1186d5ac70f0Sopenharmony_ci if (type == SND_PCM_IOPLUG_HW_ACCESS || type == SND_PCM_IOPLUG_HW_FORMAT) { 1187d5ac70f0Sopenharmony_ci SNDERR("IOPLUG: invalid parameter type %d", type); 1188d5ac70f0Sopenharmony_ci return -EINVAL; 1189d5ac70f0Sopenharmony_ci } 1190d5ac70f0Sopenharmony_ci if (type == SND_PCM_IOPLUG_HW_PERIODS) 1191d5ac70f0Sopenharmony_ci io->params[type].integer = 1; 1192d5ac70f0Sopenharmony_ci return snd_ext_parm_set_minmax(&io->params[type], min, max); 1193d5ac70f0Sopenharmony_ci} 1194d5ac70f0Sopenharmony_ci 1195d5ac70f0Sopenharmony_ci/** 1196d5ac70f0Sopenharmony_ci * \brief Reinitialize the poll and mmap status 1197d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle 1198d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 1199d5ac70f0Sopenharmony_ci * 1200d5ac70f0Sopenharmony_ci * Reinitializes the poll and the mmap status of the PCM. 1201d5ac70f0Sopenharmony_ci * Call this function to propagate the status change in the ioplug instance to 1202d5ac70f0Sopenharmony_ci * its PCM internals. 1203d5ac70f0Sopenharmony_ci */ 1204d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_reinit_status(snd_pcm_ioplug_t *ioplug) 1205d5ac70f0Sopenharmony_ci{ 1206d5ac70f0Sopenharmony_ci ioplug->pcm->poll_fd = ioplug->poll_fd; 1207d5ac70f0Sopenharmony_ci ioplug->pcm->poll_events = ioplug->poll_events; 1208d5ac70f0Sopenharmony_ci if (ioplug->flags & SND_PCM_IOPLUG_FLAG_MONOTONIC) 1209d5ac70f0Sopenharmony_ci ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_MONOTONIC; 1210d5ac70f0Sopenharmony_ci else 1211d5ac70f0Sopenharmony_ci ioplug->pcm->tstamp_type = SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY; 1212d5ac70f0Sopenharmony_ci ioplug->pcm->mmap_rw = ioplug->mmap_rw; 1213d5ac70f0Sopenharmony_ci return 0; 1214d5ac70f0Sopenharmony_ci} 1215d5ac70f0Sopenharmony_ci 1216d5ac70f0Sopenharmony_ci/** 1217d5ac70f0Sopenharmony_ci * \brief Get mmap area of ioplug 1218d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle 1219d5ac70f0Sopenharmony_ci * \return the mmap channel areas if available, or NULL 1220d5ac70f0Sopenharmony_ci * 1221d5ac70f0Sopenharmony_ci * Returns the mmap channel areas if available. When mmap_rw field is not set, 1222d5ac70f0Sopenharmony_ci * this function always returns NULL. 1223d5ac70f0Sopenharmony_ci */ 1224d5ac70f0Sopenharmony_ciconst snd_pcm_channel_area_t *snd_pcm_ioplug_mmap_areas(snd_pcm_ioplug_t *ioplug) 1225d5ac70f0Sopenharmony_ci{ 1226d5ac70f0Sopenharmony_ci if (ioplug->mmap_rw) 1227d5ac70f0Sopenharmony_ci return snd_pcm_mmap_areas(ioplug->pcm); 1228d5ac70f0Sopenharmony_ci return NULL; 1229d5ac70f0Sopenharmony_ci} 1230d5ac70f0Sopenharmony_ci 1231d5ac70f0Sopenharmony_ci/** 1232d5ac70f0Sopenharmony_ci * \brief Change the ioplug PCM status 1233d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle 1234d5ac70f0Sopenharmony_ci * \param state the PCM status 1235d5ac70f0Sopenharmony_ci * \return zero if successful or a negative error code 1236d5ac70f0Sopenharmony_ci * 1237d5ac70f0Sopenharmony_ci * Changes the PCM status of the ioplug to the given value. 1238d5ac70f0Sopenharmony_ci * This function can be used for external plugins to notify the status 1239d5ac70f0Sopenharmony_ci * change, e.g. XRUN. 1240d5ac70f0Sopenharmony_ci */ 1241d5ac70f0Sopenharmony_ciint snd_pcm_ioplug_set_state(snd_pcm_ioplug_t *ioplug, snd_pcm_state_t state) 1242d5ac70f0Sopenharmony_ci{ 1243d5ac70f0Sopenharmony_ci ioplug->state = state; 1244d5ac70f0Sopenharmony_ci return 0; 1245d5ac70f0Sopenharmony_ci} 1246d5ac70f0Sopenharmony_ci 1247d5ac70f0Sopenharmony_ci/** 1248d5ac70f0Sopenharmony_ci * \brief Get the available frames. This function can be used to calculate the 1249d5ac70f0Sopenharmony_ci * the available frames before calling #snd_pcm_avail_update() 1250d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle 1251d5ac70f0Sopenharmony_ci * \param hw_ptr hardware pointer in frames 1252d5ac70f0Sopenharmony_ci * \param appl_ptr application pointer in frames 1253d5ac70f0Sopenharmony_ci * \return available frames for the application 1254d5ac70f0Sopenharmony_ci */ 1255d5ac70f0Sopenharmony_cisnd_pcm_uframes_t snd_pcm_ioplug_avail(const snd_pcm_ioplug_t * const ioplug, 1256d5ac70f0Sopenharmony_ci const snd_pcm_uframes_t hw_ptr, 1257d5ac70f0Sopenharmony_ci const snd_pcm_uframes_t appl_ptr) 1258d5ac70f0Sopenharmony_ci{ 1259d5ac70f0Sopenharmony_ci return __snd_pcm_avail(ioplug->pcm, hw_ptr, appl_ptr); 1260d5ac70f0Sopenharmony_ci} 1261d5ac70f0Sopenharmony_ci 1262d5ac70f0Sopenharmony_ci/** 1263d5ac70f0Sopenharmony_ci * \brief Get the available frames. This function can be used to calculate the 1264d5ac70f0Sopenharmony_ci * the available frames before calling #snd_pcm_avail_update() 1265d5ac70f0Sopenharmony_ci * \param ioplug the ioplug handle 1266d5ac70f0Sopenharmony_ci * \param hw_ptr hardware pointer in frames 1267d5ac70f0Sopenharmony_ci * \param appl_ptr application pointer in frames 1268d5ac70f0Sopenharmony_ci * \return available frames for the hardware 1269d5ac70f0Sopenharmony_ci */ 1270d5ac70f0Sopenharmony_cisnd_pcm_uframes_t snd_pcm_ioplug_hw_avail(const snd_pcm_ioplug_t * const ioplug, 1271d5ac70f0Sopenharmony_ci const snd_pcm_uframes_t hw_ptr, 1272d5ac70f0Sopenharmony_ci const snd_pcm_uframes_t appl_ptr) 1273d5ac70f0Sopenharmony_ci{ 1274d5ac70f0Sopenharmony_ci /* available data/space which can be transferred by the user 1275d5ac70f0Sopenharmony_ci * application 1276d5ac70f0Sopenharmony_ci */ 1277d5ac70f0Sopenharmony_ci const snd_pcm_uframes_t user_avail = snd_pcm_ioplug_avail(ioplug, 1278d5ac70f0Sopenharmony_ci hw_ptr, 1279d5ac70f0Sopenharmony_ci appl_ptr); 1280d5ac70f0Sopenharmony_ci 1281d5ac70f0Sopenharmony_ci if (user_avail > ioplug->pcm->buffer_size) { 1282d5ac70f0Sopenharmony_ci /* there was an Xrun */ 1283d5ac70f0Sopenharmony_ci return 0; 1284d5ac70f0Sopenharmony_ci } 1285d5ac70f0Sopenharmony_ci /* available data/space which can be transferred by the DMA */ 1286d5ac70f0Sopenharmony_ci return ioplug->pcm->buffer_size - user_avail; 1287d5ac70f0Sopenharmony_ci} 1288