1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_plugin.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM 4d5ac70f0Sopenharmony_ci * \brief PCM Interface 5d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 6d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 7d5ac70f0Sopenharmony_ci * \date 2000-2001 8d5ac70f0Sopenharmony_ci */ 9d5ac70f0Sopenharmony_ci/* 10d5ac70f0Sopenharmony_ci * PCM - Common plugin code 11d5ac70f0Sopenharmony_ci * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> 12d5ac70f0Sopenharmony_ci * 13d5ac70f0Sopenharmony_ci * 14d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 15d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 16d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 17d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 18d5ac70f0Sopenharmony_ci * 19d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 20d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 21d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 23d5ac70f0Sopenharmony_ci * 24d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 25d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 26d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 27d5ac70f0Sopenharmony_ci * 28d5ac70f0Sopenharmony_ci */ 29d5ac70f0Sopenharmony_ci 30d5ac70f0Sopenharmony_ci/*! 31d5ac70f0Sopenharmony_ci 32d5ac70f0Sopenharmony_ci\page pcm_plugins PCM (digital audio) plugins 33d5ac70f0Sopenharmony_ci 34d5ac70f0Sopenharmony_ciPCM plugins extends functionality and features of PCM devices. 35d5ac70f0Sopenharmony_ciThe plugins take care about various sample conversions, sample 36d5ac70f0Sopenharmony_cicopying among channels and so on. 37d5ac70f0Sopenharmony_ci 38d5ac70f0Sopenharmony_ci\section pcm_plugins_slave Slave definition 39d5ac70f0Sopenharmony_ci 40d5ac70f0Sopenharmony_ciThe slave plugin can be specified directly with a string or the definition 41d5ac70f0Sopenharmony_cican be entered inside a compound configuration node. Some restrictions can 42d5ac70f0Sopenharmony_cibe also specified (like static rate or count of channels). 43d5ac70f0Sopenharmony_ci 44d5ac70f0Sopenharmony_ci\code 45d5ac70f0Sopenharmony_cipcm_slave.NAME { 46d5ac70f0Sopenharmony_ci pcm STR # PCM name 47d5ac70f0Sopenharmony_ci # or 48d5ac70f0Sopenharmony_ci pcm { } # PCM definition 49d5ac70f0Sopenharmony_ci format STR # Format or "unchanged" 50d5ac70f0Sopenharmony_ci channels INT # Count of channels or "unchanged" string 51d5ac70f0Sopenharmony_ci rate INT # Rate in Hz or "unchanged" string 52d5ac70f0Sopenharmony_ci period_time INT # Period time in us or "unchanged" string 53d5ac70f0Sopenharmony_ci buffer_time INT # Buffer time in us or "unchanged" string 54d5ac70f0Sopenharmony_ci} 55d5ac70f0Sopenharmony_ci\endcode 56d5ac70f0Sopenharmony_ci 57d5ac70f0Sopenharmony_ciExample: 58d5ac70f0Sopenharmony_ci 59d5ac70f0Sopenharmony_ci\code 60d5ac70f0Sopenharmony_cipcm_slave.slave_rate44100Hz { 61d5ac70f0Sopenharmony_ci pcm "hw:0,0" 62d5ac70f0Sopenharmony_ci rate 44100 63d5ac70f0Sopenharmony_ci} 64d5ac70f0Sopenharmony_ci 65d5ac70f0Sopenharmony_cipcm.rate44100Hz { 66d5ac70f0Sopenharmony_ci type plug 67d5ac70f0Sopenharmony_ci slave slave_rate44100Hz 68d5ac70f0Sopenharmony_ci} 69d5ac70f0Sopenharmony_ci\endcode 70d5ac70f0Sopenharmony_ci 71d5ac70f0Sopenharmony_ciThe equivalent configuration (in one compound): 72d5ac70f0Sopenharmony_ci 73d5ac70f0Sopenharmony_ci\code 74d5ac70f0Sopenharmony_cipcm.rate44100Hz { 75d5ac70f0Sopenharmony_ci type plug 76d5ac70f0Sopenharmony_ci slave { 77d5ac70f0Sopenharmony_ci pcm "hw:0,0" 78d5ac70f0Sopenharmony_ci rate 44100 79d5ac70f0Sopenharmony_ci } 80d5ac70f0Sopenharmony_ci} 81d5ac70f0Sopenharmony_ci\endcode 82d5ac70f0Sopenharmony_ci 83d5ac70f0Sopenharmony_ci*/ 84d5ac70f0Sopenharmony_ci 85d5ac70f0Sopenharmony_ci#include "pcm_local.h" 86d5ac70f0Sopenharmony_ci#include "pcm_plugin.h" 87d5ac70f0Sopenharmony_ci#include <limits.h> 88d5ac70f0Sopenharmony_ci 89d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 90d5ac70f0Sopenharmony_ci 91d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t 92d5ac70f0Sopenharmony_cisnd_pcm_plugin_undo_read(snd_pcm_t *pcm ATTRIBUTE_UNUSED, 93d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, 94d5ac70f0Sopenharmony_ci snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, 95d5ac70f0Sopenharmony_ci snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, 96d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED) 97d5ac70f0Sopenharmony_ci{ 98d5ac70f0Sopenharmony_ci return -EIO; 99d5ac70f0Sopenharmony_ci} 100d5ac70f0Sopenharmony_ci 101d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t 102d5ac70f0Sopenharmony_cisnd_pcm_plugin_undo_write(snd_pcm_t *pcm ATTRIBUTE_UNUSED, 103d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, 104d5ac70f0Sopenharmony_ci snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, 105d5ac70f0Sopenharmony_ci snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, 106d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_undo_size ATTRIBUTE_UNUSED) 107d5ac70f0Sopenharmony_ci{ 108d5ac70f0Sopenharmony_ci return -EIO; 109d5ac70f0Sopenharmony_ci} 110d5ac70f0Sopenharmony_ci 111d5ac70f0Sopenharmony_cisnd_pcm_sframes_t 112d5ac70f0Sopenharmony_cisnd_pcm_plugin_undo_read_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED, 113d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, 114d5ac70f0Sopenharmony_ci snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, 115d5ac70f0Sopenharmony_ci snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, 116d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_undo_size) 117d5ac70f0Sopenharmony_ci{ 118d5ac70f0Sopenharmony_ci return slave_undo_size; 119d5ac70f0Sopenharmony_ci} 120d5ac70f0Sopenharmony_ci 121d5ac70f0Sopenharmony_cisnd_pcm_sframes_t 122d5ac70f0Sopenharmony_cisnd_pcm_plugin_undo_write_generic(snd_pcm_t *pcm ATTRIBUTE_UNUSED, 123d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *res_areas ATTRIBUTE_UNUSED, 124d5ac70f0Sopenharmony_ci snd_pcm_uframes_t res_offset ATTRIBUTE_UNUSED, 125d5ac70f0Sopenharmony_ci snd_pcm_uframes_t res_size ATTRIBUTE_UNUSED, 126d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_undo_size) 127d5ac70f0Sopenharmony_ci{ 128d5ac70f0Sopenharmony_ci return slave_undo_size; 129d5ac70f0Sopenharmony_ci} 130d5ac70f0Sopenharmony_ci 131d5ac70f0Sopenharmony_civoid snd_pcm_plugin_init(snd_pcm_plugin_t *plugin) 132d5ac70f0Sopenharmony_ci{ 133d5ac70f0Sopenharmony_ci memset(plugin, 0, sizeof(snd_pcm_plugin_t)); 134d5ac70f0Sopenharmony_ci plugin->undo_read = snd_pcm_plugin_undo_read; 135d5ac70f0Sopenharmony_ci plugin->undo_write = snd_pcm_plugin_undo_write; 136d5ac70f0Sopenharmony_ci} 137d5ac70f0Sopenharmony_ci 138d5ac70f0Sopenharmony_cistatic int snd_pcm_plugin_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 139d5ac70f0Sopenharmony_ci{ 140d5ac70f0Sopenharmony_ci snd_pcm_plugin_t *plugin = pcm->private_data; 141d5ac70f0Sopenharmony_ci snd_pcm_sframes_t sd; 142d5ac70f0Sopenharmony_ci int err = snd_pcm_delay(plugin->gen.slave, &sd); 143d5ac70f0Sopenharmony_ci if (err < 0) 144d5ac70f0Sopenharmony_ci return err; 145d5ac70f0Sopenharmony_ci *delayp = sd; 146d5ac70f0Sopenharmony_ci return 0; 147d5ac70f0Sopenharmony_ci} 148d5ac70f0Sopenharmony_ci 149d5ac70f0Sopenharmony_cistatic int snd_pcm_plugin_call_init_cb(snd_pcm_t *pcm, snd_pcm_plugin_t *plugin) 150d5ac70f0Sopenharmony_ci{ 151d5ac70f0Sopenharmony_ci snd_pcm_t *slave = plugin->gen.slave; 152d5ac70f0Sopenharmony_ci int err; 153d5ac70f0Sopenharmony_ci 154d5ac70f0Sopenharmony_ci assert(pcm->boundary == slave->boundary); 155d5ac70f0Sopenharmony_ci *pcm->hw.ptr = *slave->hw.ptr; 156d5ac70f0Sopenharmony_ci *pcm->appl.ptr = *slave->appl.ptr; 157d5ac70f0Sopenharmony_ci if (plugin->init) { 158d5ac70f0Sopenharmony_ci err = plugin->init(pcm); 159d5ac70f0Sopenharmony_ci if (err < 0) 160d5ac70f0Sopenharmony_ci return err; 161d5ac70f0Sopenharmony_ci } 162d5ac70f0Sopenharmony_ci return 0; 163d5ac70f0Sopenharmony_ci} 164d5ac70f0Sopenharmony_ci 165d5ac70f0Sopenharmony_cistatic int snd_pcm_plugin_prepare(snd_pcm_t *pcm) 166d5ac70f0Sopenharmony_ci{ 167d5ac70f0Sopenharmony_ci snd_pcm_plugin_t *plugin = pcm->private_data; 168d5ac70f0Sopenharmony_ci int err; 169d5ac70f0Sopenharmony_ci err = snd_pcm_prepare(plugin->gen.slave); 170d5ac70f0Sopenharmony_ci if (err < 0) 171d5ac70f0Sopenharmony_ci return err; 172d5ac70f0Sopenharmony_ci return snd_pcm_plugin_call_init_cb(pcm, plugin); 173d5ac70f0Sopenharmony_ci} 174d5ac70f0Sopenharmony_ci 175d5ac70f0Sopenharmony_cistatic int snd_pcm_plugin_reset(snd_pcm_t *pcm) 176d5ac70f0Sopenharmony_ci{ 177d5ac70f0Sopenharmony_ci snd_pcm_plugin_t *plugin = pcm->private_data; 178d5ac70f0Sopenharmony_ci int err; 179d5ac70f0Sopenharmony_ci err = snd_pcm_reset(plugin->gen.slave); 180d5ac70f0Sopenharmony_ci if (err < 0) 181d5ac70f0Sopenharmony_ci return err; 182d5ac70f0Sopenharmony_ci return snd_pcm_plugin_call_init_cb(pcm, plugin); 183d5ac70f0Sopenharmony_ci} 184d5ac70f0Sopenharmony_ci 185d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_rewindable(snd_pcm_t *pcm) 186d5ac70f0Sopenharmony_ci{ 187d5ac70f0Sopenharmony_ci return snd_pcm_mmap_hw_rewindable(pcm); 188d5ac70f0Sopenharmony_ci} 189d5ac70f0Sopenharmony_ci 190d5ac70f0Sopenharmony_cisnd_pcm_sframes_t snd_pcm_plugin_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 191d5ac70f0Sopenharmony_ci{ 192d5ac70f0Sopenharmony_ci snd_pcm_plugin_t *plugin = pcm->private_data; 193d5ac70f0Sopenharmony_ci snd_pcm_sframes_t n = snd_pcm_plugin_rewindable(pcm); 194d5ac70f0Sopenharmony_ci snd_pcm_sframes_t sframes; 195d5ac70f0Sopenharmony_ci 196d5ac70f0Sopenharmony_ci if ((snd_pcm_uframes_t)n < frames) 197d5ac70f0Sopenharmony_ci frames = n; 198d5ac70f0Sopenharmony_ci if (frames == 0) 199d5ac70f0Sopenharmony_ci return 0; 200d5ac70f0Sopenharmony_ci 201d5ac70f0Sopenharmony_ci sframes = frames; 202d5ac70f0Sopenharmony_ci sframes = snd_pcm_rewind(plugin->gen.slave, sframes); 203d5ac70f0Sopenharmony_ci if (sframes < 0) 204d5ac70f0Sopenharmony_ci return sframes; 205d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_backward(pcm, (snd_pcm_uframes_t) sframes); 206d5ac70f0Sopenharmony_ci return (snd_pcm_sframes_t) sframes; 207d5ac70f0Sopenharmony_ci} 208d5ac70f0Sopenharmony_ci 209d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_forwardable(snd_pcm_t *pcm) 210d5ac70f0Sopenharmony_ci{ 211d5ac70f0Sopenharmony_ci return snd_pcm_mmap_avail(pcm); 212d5ac70f0Sopenharmony_ci} 213d5ac70f0Sopenharmony_ci 214d5ac70f0Sopenharmony_cisnd_pcm_sframes_t snd_pcm_plugin_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 215d5ac70f0Sopenharmony_ci{ 216d5ac70f0Sopenharmony_ci snd_pcm_plugin_t *plugin = pcm->private_data; 217d5ac70f0Sopenharmony_ci snd_pcm_sframes_t n = snd_pcm_plugin_forwardable(pcm); 218d5ac70f0Sopenharmony_ci snd_pcm_sframes_t sframes; 219d5ac70f0Sopenharmony_ci 220d5ac70f0Sopenharmony_ci if ((snd_pcm_uframes_t)n < frames) 221d5ac70f0Sopenharmony_ci frames = n; 222d5ac70f0Sopenharmony_ci if (frames == 0) 223d5ac70f0Sopenharmony_ci return 0; 224d5ac70f0Sopenharmony_ci 225d5ac70f0Sopenharmony_ci sframes = frames; 226d5ac70f0Sopenharmony_ci sframes = INTERNAL(snd_pcm_forward)(plugin->gen.slave, sframes); 227d5ac70f0Sopenharmony_ci if (sframes < 0) 228d5ac70f0Sopenharmony_ci return sframes; 229d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, (snd_pcm_uframes_t) frames); 230d5ac70f0Sopenharmony_ci return (snd_pcm_sframes_t) frames; 231d5ac70f0Sopenharmony_ci} 232d5ac70f0Sopenharmony_ci 233d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_write_areas(snd_pcm_t *pcm, 234d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 235d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 236d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 237d5ac70f0Sopenharmony_ci{ 238d5ac70f0Sopenharmony_ci snd_pcm_plugin_t *plugin = pcm->private_data; 239d5ac70f0Sopenharmony_ci snd_pcm_t *slave = plugin->gen.slave; 240d5ac70f0Sopenharmony_ci snd_pcm_uframes_t xfer = 0; 241d5ac70f0Sopenharmony_ci snd_pcm_sframes_t result; 242d5ac70f0Sopenharmony_ci int err; 243d5ac70f0Sopenharmony_ci 244d5ac70f0Sopenharmony_ci while (size > 0) { 245d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames = size; 246d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas; 247d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset; 248d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_frames = ULONG_MAX; 249d5ac70f0Sopenharmony_ci 250d5ac70f0Sopenharmony_ci result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); 251d5ac70f0Sopenharmony_ci if (result < 0) { 252d5ac70f0Sopenharmony_ci err = result; 253d5ac70f0Sopenharmony_ci goto error; 254d5ac70f0Sopenharmony_ci } 255d5ac70f0Sopenharmony_ci if (slave_frames == 0) 256d5ac70f0Sopenharmony_ci break; 257d5ac70f0Sopenharmony_ci frames = plugin->write(pcm, areas, offset, frames, 258d5ac70f0Sopenharmony_ci slave_areas, slave_offset, &slave_frames); 259d5ac70f0Sopenharmony_ci if (CHECK_SANITY(slave_frames > snd_pcm_mmap_playback_avail(slave))) { 260d5ac70f0Sopenharmony_ci SNDMSG("write overflow %ld > %ld", slave_frames, 261d5ac70f0Sopenharmony_ci snd_pcm_mmap_playback_avail(slave)); 262d5ac70f0Sopenharmony_ci err = -EPIPE; 263d5ac70f0Sopenharmony_ci goto error; 264d5ac70f0Sopenharmony_ci } 265d5ac70f0Sopenharmony_ci result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); 266d5ac70f0Sopenharmony_ci if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { 267d5ac70f0Sopenharmony_ci snd_pcm_sframes_t res; 268d5ac70f0Sopenharmony_ci res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result); 269d5ac70f0Sopenharmony_ci if (res < 0) { 270d5ac70f0Sopenharmony_ci err = res; 271d5ac70f0Sopenharmony_ci goto error; 272d5ac70f0Sopenharmony_ci } 273d5ac70f0Sopenharmony_ci frames -= res; 274d5ac70f0Sopenharmony_ci } 275d5ac70f0Sopenharmony_ci if (result <= 0) { 276d5ac70f0Sopenharmony_ci err = result; 277d5ac70f0Sopenharmony_ci goto error; 278d5ac70f0Sopenharmony_ci } 279d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, frames); 280d5ac70f0Sopenharmony_ci offset += frames; 281d5ac70f0Sopenharmony_ci xfer += frames; 282d5ac70f0Sopenharmony_ci size -= frames; 283d5ac70f0Sopenharmony_ci } 284d5ac70f0Sopenharmony_ci return (snd_pcm_sframes_t)xfer; 285d5ac70f0Sopenharmony_ci 286d5ac70f0Sopenharmony_ci error: 287d5ac70f0Sopenharmony_ci return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; 288d5ac70f0Sopenharmony_ci} 289d5ac70f0Sopenharmony_ci 290d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_read_areas(snd_pcm_t *pcm, 291d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 292d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 293d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 294d5ac70f0Sopenharmony_ci{ 295d5ac70f0Sopenharmony_ci snd_pcm_plugin_t *plugin = pcm->private_data; 296d5ac70f0Sopenharmony_ci snd_pcm_t *slave = plugin->gen.slave; 297d5ac70f0Sopenharmony_ci snd_pcm_uframes_t xfer = 0; 298d5ac70f0Sopenharmony_ci snd_pcm_sframes_t result; 299d5ac70f0Sopenharmony_ci int err; 300d5ac70f0Sopenharmony_ci 301d5ac70f0Sopenharmony_ci while (size > 0) { 302d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames = size; 303d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas; 304d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset; 305d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_frames = ULONG_MAX; 306d5ac70f0Sopenharmony_ci 307d5ac70f0Sopenharmony_ci result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); 308d5ac70f0Sopenharmony_ci if (result < 0) { 309d5ac70f0Sopenharmony_ci err = result; 310d5ac70f0Sopenharmony_ci goto error; 311d5ac70f0Sopenharmony_ci } 312d5ac70f0Sopenharmony_ci if (slave_frames == 0) 313d5ac70f0Sopenharmony_ci break; 314d5ac70f0Sopenharmony_ci frames = (plugin->read)(pcm, areas, offset, frames, 315d5ac70f0Sopenharmony_ci slave_areas, slave_offset, &slave_frames); 316d5ac70f0Sopenharmony_ci if (CHECK_SANITY(slave_frames > snd_pcm_mmap_capture_avail(slave))) { 317d5ac70f0Sopenharmony_ci SNDMSG("read overflow %ld > %ld", slave_frames, 318d5ac70f0Sopenharmony_ci snd_pcm_mmap_playback_avail(slave)); 319d5ac70f0Sopenharmony_ci err = -EPIPE; 320d5ac70f0Sopenharmony_ci goto error; 321d5ac70f0Sopenharmony_ci } 322d5ac70f0Sopenharmony_ci result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); 323d5ac70f0Sopenharmony_ci if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { 324d5ac70f0Sopenharmony_ci snd_pcm_sframes_t res; 325d5ac70f0Sopenharmony_ci 326d5ac70f0Sopenharmony_ci res = plugin->undo_read(slave, areas, offset, frames, slave_frames - result); 327d5ac70f0Sopenharmony_ci if (res < 0) { 328d5ac70f0Sopenharmony_ci err = res; 329d5ac70f0Sopenharmony_ci goto error; 330d5ac70f0Sopenharmony_ci } 331d5ac70f0Sopenharmony_ci frames -= res; 332d5ac70f0Sopenharmony_ci } 333d5ac70f0Sopenharmony_ci if (result <= 0) { 334d5ac70f0Sopenharmony_ci err = result; 335d5ac70f0Sopenharmony_ci goto error; 336d5ac70f0Sopenharmony_ci } 337d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, frames); 338d5ac70f0Sopenharmony_ci offset += frames; 339d5ac70f0Sopenharmony_ci xfer += frames; 340d5ac70f0Sopenharmony_ci size -= frames; 341d5ac70f0Sopenharmony_ci } 342d5ac70f0Sopenharmony_ci return (snd_pcm_sframes_t)xfer; 343d5ac70f0Sopenharmony_ci 344d5ac70f0Sopenharmony_ci error: 345d5ac70f0Sopenharmony_ci return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; 346d5ac70f0Sopenharmony_ci} 347d5ac70f0Sopenharmony_ci 348d5ac70f0Sopenharmony_ci 349d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t 350d5ac70f0Sopenharmony_cisnd_pcm_plugin_writei(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size) 351d5ac70f0Sopenharmony_ci{ 352d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 353d5ac70f0Sopenharmony_ci snd_pcm_areas_from_buf(pcm, areas, (void*)buffer); 354d5ac70f0Sopenharmony_ci return snd_pcm_write_areas(pcm, areas, 0, size, 355d5ac70f0Sopenharmony_ci snd_pcm_plugin_write_areas); 356d5ac70f0Sopenharmony_ci} 357d5ac70f0Sopenharmony_ci 358d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t 359d5ac70f0Sopenharmony_cisnd_pcm_plugin_writen(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) 360d5ac70f0Sopenharmony_ci{ 361d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 362d5ac70f0Sopenharmony_ci snd_pcm_areas_from_bufs(pcm, areas, bufs); 363d5ac70f0Sopenharmony_ci return snd_pcm_write_areas(pcm, areas, 0, size, 364d5ac70f0Sopenharmony_ci snd_pcm_plugin_write_areas); 365d5ac70f0Sopenharmony_ci} 366d5ac70f0Sopenharmony_ci 367d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t 368d5ac70f0Sopenharmony_cisnd_pcm_plugin_readi(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size) 369d5ac70f0Sopenharmony_ci{ 370d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 371d5ac70f0Sopenharmony_ci snd_pcm_areas_from_buf(pcm, areas, buffer); 372d5ac70f0Sopenharmony_ci return snd_pcm_read_areas(pcm, areas, 0, size, 373d5ac70f0Sopenharmony_ci snd_pcm_plugin_read_areas); 374d5ac70f0Sopenharmony_ci} 375d5ac70f0Sopenharmony_ci 376d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t 377d5ac70f0Sopenharmony_cisnd_pcm_plugin_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size) 378d5ac70f0Sopenharmony_ci{ 379d5ac70f0Sopenharmony_ci snd_pcm_channel_area_t areas[pcm->channels]; 380d5ac70f0Sopenharmony_ci snd_pcm_areas_from_bufs(pcm, areas, bufs); 381d5ac70f0Sopenharmony_ci return snd_pcm_read_areas(pcm, areas, 0, size, 382d5ac70f0Sopenharmony_ci snd_pcm_plugin_read_areas); 383d5ac70f0Sopenharmony_ci} 384d5ac70f0Sopenharmony_ci 385d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t 386d5ac70f0Sopenharmony_cisnd_pcm_plugin_mmap_commit(snd_pcm_t *pcm, 387d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, 388d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 389d5ac70f0Sopenharmony_ci{ 390d5ac70f0Sopenharmony_ci snd_pcm_plugin_t *plugin = pcm->private_data; 391d5ac70f0Sopenharmony_ci snd_pcm_t *slave = plugin->gen.slave; 392d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas; 393d5ac70f0Sopenharmony_ci snd_pcm_uframes_t appl_offset; 394d5ac70f0Sopenharmony_ci snd_pcm_sframes_t slave_size; 395d5ac70f0Sopenharmony_ci snd_pcm_sframes_t xfer; 396d5ac70f0Sopenharmony_ci int err; 397d5ac70f0Sopenharmony_ci 398d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_CAPTURE) { 399d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, size); 400d5ac70f0Sopenharmony_ci return size; 401d5ac70f0Sopenharmony_ci } 402d5ac70f0Sopenharmony_ci slave_size = snd_pcm_avail_update(slave); 403d5ac70f0Sopenharmony_ci if (slave_size < 0) 404d5ac70f0Sopenharmony_ci return slave_size; 405d5ac70f0Sopenharmony_ci areas = snd_pcm_mmap_areas(pcm); 406d5ac70f0Sopenharmony_ci appl_offset = snd_pcm_mmap_offset(pcm); 407d5ac70f0Sopenharmony_ci xfer = 0; 408d5ac70f0Sopenharmony_ci while (size > 0 && slave_size > 0) { 409d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames = size; 410d5ac70f0Sopenharmony_ci snd_pcm_uframes_t cont = pcm->buffer_size - appl_offset; 411d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas; 412d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset; 413d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_frames = ULONG_MAX; 414d5ac70f0Sopenharmony_ci snd_pcm_sframes_t result; 415d5ac70f0Sopenharmony_ci 416d5ac70f0Sopenharmony_ci result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); 417d5ac70f0Sopenharmony_ci if (result < 0) { 418d5ac70f0Sopenharmony_ci err = result; 419d5ac70f0Sopenharmony_ci goto error; 420d5ac70f0Sopenharmony_ci } 421d5ac70f0Sopenharmony_ci if (frames > cont) 422d5ac70f0Sopenharmony_ci frames = cont; 423d5ac70f0Sopenharmony_ci frames = plugin->write(pcm, areas, appl_offset, frames, 424d5ac70f0Sopenharmony_ci slave_areas, slave_offset, &slave_frames); 425d5ac70f0Sopenharmony_ci result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); 426d5ac70f0Sopenharmony_ci if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { 427d5ac70f0Sopenharmony_ci snd_pcm_sframes_t res; 428d5ac70f0Sopenharmony_ci 429d5ac70f0Sopenharmony_ci res = plugin->undo_write(pcm, slave_areas, slave_offset + result, slave_frames, slave_frames - result); 430d5ac70f0Sopenharmony_ci if (res < 0) { 431d5ac70f0Sopenharmony_ci err = res; 432d5ac70f0Sopenharmony_ci goto error; 433d5ac70f0Sopenharmony_ci } 434d5ac70f0Sopenharmony_ci frames -= res; 435d5ac70f0Sopenharmony_ci } 436d5ac70f0Sopenharmony_ci if (result <= 0) { 437d5ac70f0Sopenharmony_ci err = result; 438d5ac70f0Sopenharmony_ci goto error; 439d5ac70f0Sopenharmony_ci } 440d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, frames); 441d5ac70f0Sopenharmony_ci if (frames == cont) 442d5ac70f0Sopenharmony_ci appl_offset = 0; 443d5ac70f0Sopenharmony_ci else 444d5ac70f0Sopenharmony_ci appl_offset += result; 445d5ac70f0Sopenharmony_ci size -= frames; 446d5ac70f0Sopenharmony_ci slave_size -= frames; 447d5ac70f0Sopenharmony_ci xfer += frames; 448d5ac70f0Sopenharmony_ci } 449d5ac70f0Sopenharmony_ci if (CHECK_SANITY(size)) { 450d5ac70f0Sopenharmony_ci SNDMSG("short commit: %ld", size); 451d5ac70f0Sopenharmony_ci return -EPIPE; 452d5ac70f0Sopenharmony_ci } 453d5ac70f0Sopenharmony_ci return xfer; 454d5ac70f0Sopenharmony_ci 455d5ac70f0Sopenharmony_ci error: 456d5ac70f0Sopenharmony_ci return xfer > 0 ? xfer : err; 457d5ac70f0Sopenharmony_ci} 458d5ac70f0Sopenharmony_ci 459d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t 460d5ac70f0Sopenharmony_cisnd_pcm_plugin_sync_hw_ptr_capture(snd_pcm_t *pcm, 461d5ac70f0Sopenharmony_ci snd_pcm_sframes_t slave_size) 462d5ac70f0Sopenharmony_ci{ 463d5ac70f0Sopenharmony_ci snd_pcm_plugin_t *plugin = pcm->private_data; 464d5ac70f0Sopenharmony_ci snd_pcm_t *slave = plugin->gen.slave; 465d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas; 466d5ac70f0Sopenharmony_ci snd_pcm_uframes_t xfer, hw_offset, size; 467d5ac70f0Sopenharmony_ci int err; 468d5ac70f0Sopenharmony_ci 469d5ac70f0Sopenharmony_ci xfer = snd_pcm_mmap_capture_avail(pcm); 470d5ac70f0Sopenharmony_ci size = pcm->buffer_size - xfer; 471d5ac70f0Sopenharmony_ci areas = snd_pcm_mmap_areas(pcm); 472d5ac70f0Sopenharmony_ci hw_offset = snd_pcm_mmap_hw_offset(pcm); 473d5ac70f0Sopenharmony_ci while (size > 0 && slave_size > 0) { 474d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames = size; 475d5ac70f0Sopenharmony_ci snd_pcm_uframes_t cont = pcm->buffer_size - hw_offset; 476d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas; 477d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset; 478d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_frames = ULONG_MAX; 479d5ac70f0Sopenharmony_ci snd_pcm_sframes_t result; 480d5ac70f0Sopenharmony_ci /* As mentioned in the ALSA API (see pcm/pcm.c:942): 481d5ac70f0Sopenharmony_ci * The function #snd_pcm_avail_update() 482d5ac70f0Sopenharmony_ci * have to be called before any mmap begin+commit operation. 483d5ac70f0Sopenharmony_ci * Otherwise the snd_pcm_areas_copy will not called a second time. 484d5ac70f0Sopenharmony_ci * But this is needed, if the ring buffer wrap is reached and 485d5ac70f0Sopenharmony_ci * there is more data available. 486d5ac70f0Sopenharmony_ci */ 487d5ac70f0Sopenharmony_ci slave_size = snd_pcm_avail_update(slave); 488d5ac70f0Sopenharmony_ci result = snd_pcm_mmap_begin(slave, &slave_areas, &slave_offset, &slave_frames); 489d5ac70f0Sopenharmony_ci if (result < 0) { 490d5ac70f0Sopenharmony_ci err = result; 491d5ac70f0Sopenharmony_ci goto error; 492d5ac70f0Sopenharmony_ci } 493d5ac70f0Sopenharmony_ci if (frames > cont) 494d5ac70f0Sopenharmony_ci frames = cont; 495d5ac70f0Sopenharmony_ci frames = (plugin->read)(pcm, areas, hw_offset, frames, 496d5ac70f0Sopenharmony_ci slave_areas, slave_offset, &slave_frames); 497d5ac70f0Sopenharmony_ci result = snd_pcm_mmap_commit(slave, slave_offset, slave_frames); 498d5ac70f0Sopenharmony_ci if (result > 0 && (snd_pcm_uframes_t)result != slave_frames) { 499d5ac70f0Sopenharmony_ci snd_pcm_sframes_t res; 500d5ac70f0Sopenharmony_ci res = plugin->undo_read(slave, areas, hw_offset, frames, slave_frames - result); 501d5ac70f0Sopenharmony_ci if (res < 0) { 502d5ac70f0Sopenharmony_ci err = res; 503d5ac70f0Sopenharmony_ci goto error; 504d5ac70f0Sopenharmony_ci } 505d5ac70f0Sopenharmony_ci frames -= res; 506d5ac70f0Sopenharmony_ci } 507d5ac70f0Sopenharmony_ci if (result <= 0) { 508d5ac70f0Sopenharmony_ci err = result; 509d5ac70f0Sopenharmony_ci goto error; 510d5ac70f0Sopenharmony_ci } 511d5ac70f0Sopenharmony_ci snd_pcm_mmap_hw_forward(pcm, frames); 512d5ac70f0Sopenharmony_ci if (frames == cont) 513d5ac70f0Sopenharmony_ci hw_offset = 0; 514d5ac70f0Sopenharmony_ci else 515d5ac70f0Sopenharmony_ci hw_offset += frames; 516d5ac70f0Sopenharmony_ci size -= frames; 517d5ac70f0Sopenharmony_ci slave_size -= slave_frames; 518d5ac70f0Sopenharmony_ci xfer += frames; 519d5ac70f0Sopenharmony_ci } 520d5ac70f0Sopenharmony_ci return (snd_pcm_sframes_t)xfer; 521d5ac70f0Sopenharmony_cierror: 522d5ac70f0Sopenharmony_ci return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; 523d5ac70f0Sopenharmony_ci} 524d5ac70f0Sopenharmony_ci 525d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_sync_hw_ptr(snd_pcm_t *pcm, 526d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_hw_ptr, 527d5ac70f0Sopenharmony_ci snd_pcm_sframes_t slave_size) 528d5ac70f0Sopenharmony_ci{ 529d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_CAPTURE && 530d5ac70f0Sopenharmony_ci pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && 531d5ac70f0Sopenharmony_ci pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) 532d5ac70f0Sopenharmony_ci return snd_pcm_plugin_sync_hw_ptr_capture(pcm, slave_size); 533d5ac70f0Sopenharmony_ci *pcm->hw.ptr = slave_hw_ptr; 534d5ac70f0Sopenharmony_ci return slave_size; 535d5ac70f0Sopenharmony_ci} 536d5ac70f0Sopenharmony_ci 537d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm) 538d5ac70f0Sopenharmony_ci{ 539d5ac70f0Sopenharmony_ci snd_pcm_plugin_t *plugin = pcm->private_data; 540d5ac70f0Sopenharmony_ci snd_pcm_t *slave = plugin->gen.slave; 541d5ac70f0Sopenharmony_ci snd_pcm_sframes_t slave_size; 542d5ac70f0Sopenharmony_ci 543d5ac70f0Sopenharmony_ci slave_size = snd_pcm_avail_update(slave); 544d5ac70f0Sopenharmony_ci return snd_pcm_plugin_sync_hw_ptr(pcm, *slave->hw.ptr, slave_size); 545d5ac70f0Sopenharmony_ci} 546d5ac70f0Sopenharmony_ci 547d5ac70f0Sopenharmony_cistatic int snd_pcm_plugin_status(snd_pcm_t *pcm, snd_pcm_status_t * status) 548d5ac70f0Sopenharmony_ci{ 549d5ac70f0Sopenharmony_ci snd_pcm_plugin_t *plugin = pcm->private_data; 550d5ac70f0Sopenharmony_ci snd_pcm_sframes_t err, diff; 551d5ac70f0Sopenharmony_ci 552d5ac70f0Sopenharmony_ci err = snd_pcm_status(plugin->gen.slave, status); 553d5ac70f0Sopenharmony_ci if (err < 0) 554d5ac70f0Sopenharmony_ci return err; 555d5ac70f0Sopenharmony_ci snd_pcm_plugin_sync_hw_ptr(pcm, status->hw_ptr, status->avail); 556d5ac70f0Sopenharmony_ci /* 557d5ac70f0Sopenharmony_ci * For capture stream, the situation is more complicated, because 558d5ac70f0Sopenharmony_ci * snd_pcm_plugin_avail_update() commits the data to the slave pcm. 559d5ac70f0Sopenharmony_ci * It means that the slave appl_ptr is updated. Calculate diff and 560d5ac70f0Sopenharmony_ci * update the delay and avail. 561d5ac70f0Sopenharmony_ci * 562d5ac70f0Sopenharmony_ci * This resolves the data inconsistency for immediate calls: 563d5ac70f0Sopenharmony_ci * snd_pcm_avail_update() 564d5ac70f0Sopenharmony_ci * snd_pcm_status() 565d5ac70f0Sopenharmony_ci */ 566d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_CAPTURE) { 567d5ac70f0Sopenharmony_ci diff = pcm_frame_diff(status->appl_ptr, *pcm->appl.ptr, pcm->boundary); 568d5ac70f0Sopenharmony_ci status->appl_ptr = *pcm->appl.ptr; 569d5ac70f0Sopenharmony_ci status->avail += diff; 570d5ac70f0Sopenharmony_ci status->delay += diff; 571d5ac70f0Sopenharmony_ci } else { 572d5ac70f0Sopenharmony_ci assert(status->appl_ptr == *pcm->appl.ptr); 573d5ac70f0Sopenharmony_ci } 574d5ac70f0Sopenharmony_ci return 0; 575d5ac70f0Sopenharmony_ci} 576d5ac70f0Sopenharmony_ci 577d5ac70f0Sopenharmony_ciint snd_pcm_plugin_may_wait_for_avail_min_conv( 578d5ac70f0Sopenharmony_ci snd_pcm_t *pcm, 579d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail, 580d5ac70f0Sopenharmony_ci snd_pcm_uframes_t (*conv)(snd_pcm_t *, snd_pcm_uframes_t)) 581d5ac70f0Sopenharmony_ci{ 582d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_CAPTURE && 583d5ac70f0Sopenharmony_ci pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED && 584d5ac70f0Sopenharmony_ci pcm->access != SND_PCM_ACCESS_RW_NONINTERLEAVED) { 585d5ac70f0Sopenharmony_ci /* mmap access on capture device already consumes data from 586d5ac70f0Sopenharmony_ci * slave in avail_update operation. Entering snd_pcm_wait after 587d5ac70f0Sopenharmony_ci * having already consumed some fragments leads to waiting for 588d5ac70f0Sopenharmony_ci * too long time, as slave will unnecessarily wait for avail_min 589d5ac70f0Sopenharmony_ci * condition reached again. To avoid unnecessary wait times we 590d5ac70f0Sopenharmony_ci * adapt the avail_min threshold on slave dynamically. Just 591d5ac70f0Sopenharmony_ci * modifying slave->avail_min as a shortcut and lightweight 592d5ac70f0Sopenharmony_ci * solution does not work for all slave plugin types and in 593d5ac70f0Sopenharmony_ci * addition it will not propagate the change through all 594d5ac70f0Sopenharmony_ci * downstream plugins, so we have to use the sw_params API. 595d5ac70f0Sopenharmony_ci * note: reading fragmental parts from slave will only happen 596d5ac70f0Sopenharmony_ci * in case 597d5ac70f0Sopenharmony_ci * a) the slave can provide contineous hw_ptr between periods 598d5ac70f0Sopenharmony_ci * b) avail_min does not match one slave_period 599d5ac70f0Sopenharmony_ci */ 600d5ac70f0Sopenharmony_ci snd_pcm_generic_t *generic = pcm->private_data; 601d5ac70f0Sopenharmony_ci /* 602d5ac70f0Sopenharmony_ci * do not use snd_pcm_plugin_t pointer here 603d5ac70f0Sopenharmony_ci * this code is used from the generic plugins, too 604d5ac70f0Sopenharmony_ci */ 605d5ac70f0Sopenharmony_ci snd_pcm_t *slave = generic->slave; 606d5ac70f0Sopenharmony_ci snd_pcm_uframes_t needed_slave_avail_min; 607d5ac70f0Sopenharmony_ci snd_pcm_sframes_t available; 608d5ac70f0Sopenharmony_ci 609d5ac70f0Sopenharmony_ci /* update, as it might have changed. This will also call 610d5ac70f0Sopenharmony_ci * avail_update on slave and also can return error 611d5ac70f0Sopenharmony_ci */ 612d5ac70f0Sopenharmony_ci available = snd_pcm_avail_update(pcm); 613d5ac70f0Sopenharmony_ci if (available < 0) 614d5ac70f0Sopenharmony_ci return 0; 615d5ac70f0Sopenharmony_ci 616d5ac70f0Sopenharmony_ci if ((snd_pcm_uframes_t)available >= pcm->avail_min) 617d5ac70f0Sopenharmony_ci /* don't wait at all. As we can't configure avail_min 618d5ac70f0Sopenharmony_ci * of slave to 0 return here 619d5ac70f0Sopenharmony_ci */ 620d5ac70f0Sopenharmony_ci return 0; 621d5ac70f0Sopenharmony_ci 622d5ac70f0Sopenharmony_ci needed_slave_avail_min = pcm->avail_min - available; 623d5ac70f0Sopenharmony_ci 624d5ac70f0Sopenharmony_ci /* proportional adaption if rate converter is in place.. 625d5ac70f0Sopenharmony_ci * Can happen only on built-in rate plugin. 626d5ac70f0Sopenharmony_ci * This code is also used by extplug, but extplug does not allow to alter the sampling rate. 627d5ac70f0Sopenharmony_ci */ 628d5ac70f0Sopenharmony_ci if (conv) 629d5ac70f0Sopenharmony_ci needed_slave_avail_min = conv(pcm, needed_slave_avail_min); 630d5ac70f0Sopenharmony_ci 631d5ac70f0Sopenharmony_ci if (slave->avail_min != needed_slave_avail_min) { 632d5ac70f0Sopenharmony_ci snd_pcm_sw_params_t *swparams; 633d5ac70f0Sopenharmony_ci snd_pcm_sw_params_alloca(&swparams); 634d5ac70f0Sopenharmony_ci /* pray that changing sw_params while running is 635d5ac70f0Sopenharmony_ci * properly implemented in all downstream plugins... 636d5ac70f0Sopenharmony_ci * it's legal but not commonly used. 637d5ac70f0Sopenharmony_ci */ 638d5ac70f0Sopenharmony_ci snd_pcm_sw_params_current(slave, swparams); 639d5ac70f0Sopenharmony_ci /* snd_pcm_sw_params_set_avail_min() restricts setting 640d5ac70f0Sopenharmony_ci * to >= period size. This conflicts at least with our 641d5ac70f0Sopenharmony_ci * dshare patch which allows combining multiple periods 642d5ac70f0Sopenharmony_ci * or with slaves which return hw postions between 643d5ac70f0Sopenharmony_ci * periods -> set directly in sw_param structure 644d5ac70f0Sopenharmony_ci */ 645d5ac70f0Sopenharmony_ci swparams->avail_min = needed_slave_avail_min; 646d5ac70f0Sopenharmony_ci snd_pcm_sw_params(slave, swparams); 647d5ac70f0Sopenharmony_ci } 648d5ac70f0Sopenharmony_ci avail = available; 649d5ac70f0Sopenharmony_ci } 650d5ac70f0Sopenharmony_ci return snd_pcm_generic_may_wait_for_avail_min(pcm, avail); 651d5ac70f0Sopenharmony_ci} 652d5ac70f0Sopenharmony_ci 653d5ac70f0Sopenharmony_ciint snd_pcm_plugin_may_wait_for_avail_min(snd_pcm_t *pcm, 654d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail) 655d5ac70f0Sopenharmony_ci{ 656d5ac70f0Sopenharmony_ci return snd_pcm_plugin_may_wait_for_avail_min_conv(pcm, avail, NULL); 657d5ac70f0Sopenharmony_ci} 658d5ac70f0Sopenharmony_ci 659d5ac70f0Sopenharmony_ciconst snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = { 660d5ac70f0Sopenharmony_ci .status = snd_pcm_plugin_status, 661d5ac70f0Sopenharmony_ci .state = snd_pcm_generic_state, 662d5ac70f0Sopenharmony_ci .hwsync = snd_pcm_generic_hwsync, 663d5ac70f0Sopenharmony_ci .delay = snd_pcm_plugin_delay, 664d5ac70f0Sopenharmony_ci .prepare = snd_pcm_plugin_prepare, 665d5ac70f0Sopenharmony_ci .reset = snd_pcm_plugin_reset, 666d5ac70f0Sopenharmony_ci .start = snd_pcm_generic_start, 667d5ac70f0Sopenharmony_ci .drop = snd_pcm_generic_drop, 668d5ac70f0Sopenharmony_ci .drain = snd_pcm_generic_drain, 669d5ac70f0Sopenharmony_ci .pause = snd_pcm_generic_pause, 670d5ac70f0Sopenharmony_ci .rewindable = snd_pcm_plugin_rewindable, 671d5ac70f0Sopenharmony_ci .rewind = snd_pcm_plugin_rewind, 672d5ac70f0Sopenharmony_ci .forwardable = snd_pcm_plugin_forwardable, 673d5ac70f0Sopenharmony_ci .forward = snd_pcm_plugin_forward, 674d5ac70f0Sopenharmony_ci .resume = snd_pcm_generic_resume, 675d5ac70f0Sopenharmony_ci .link = snd_pcm_generic_link, 676d5ac70f0Sopenharmony_ci .link_slaves = snd_pcm_generic_link_slaves, 677d5ac70f0Sopenharmony_ci .unlink = snd_pcm_generic_unlink, 678d5ac70f0Sopenharmony_ci .writei = snd_pcm_plugin_writei, 679d5ac70f0Sopenharmony_ci .writen = snd_pcm_plugin_writen, 680d5ac70f0Sopenharmony_ci .readi = snd_pcm_plugin_readi, 681d5ac70f0Sopenharmony_ci .readn = snd_pcm_plugin_readn, 682d5ac70f0Sopenharmony_ci .avail_update = snd_pcm_plugin_avail_update, 683d5ac70f0Sopenharmony_ci .mmap_commit = snd_pcm_plugin_mmap_commit, 684d5ac70f0Sopenharmony_ci .htimestamp = snd_pcm_generic_htimestamp, 685d5ac70f0Sopenharmony_ci .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, 686d5ac70f0Sopenharmony_ci .poll_descriptors = snd_pcm_generic_poll_descriptors, 687d5ac70f0Sopenharmony_ci .poll_revents = snd_pcm_generic_poll_revents, 688d5ac70f0Sopenharmony_ci .may_wait_for_avail_min = snd_pcm_plugin_may_wait_for_avail_min, 689d5ac70f0Sopenharmony_ci}; 690d5ac70f0Sopenharmony_ci 691d5ac70f0Sopenharmony_ci#endif 692