1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_share.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM_Plugins 4d5ac70f0Sopenharmony_ci * \brief PCM Share Plugin Interface 5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 6d5ac70f0Sopenharmony_ci * \date 2000-2001 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * PCM - Share 10d5ac70f0Sopenharmony_ci * Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org> 11d5ac70f0Sopenharmony_ci * 12d5ac70f0Sopenharmony_ci * 13d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 14d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 15d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 16d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 17d5ac70f0Sopenharmony_ci * 18d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 19d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 20d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 22d5ac70f0Sopenharmony_ci * 23d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 24d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 25d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 26d5ac70f0Sopenharmony_ci * 27d5ac70f0Sopenharmony_ci */ 28d5ac70f0Sopenharmony_ci 29d5ac70f0Sopenharmony_ci#include "pcm_local.h" 30d5ac70f0Sopenharmony_ci#include <stdio.h> 31d5ac70f0Sopenharmony_ci#include <stdlib.h> 32d5ac70f0Sopenharmony_ci#include <limits.h> 33d5ac70f0Sopenharmony_ci#include <unistd.h> 34d5ac70f0Sopenharmony_ci#include <string.h> 35d5ac70f0Sopenharmony_ci#include <signal.h> 36d5ac70f0Sopenharmony_ci#include <math.h> 37d5ac70f0Sopenharmony_ci#include <sys/socket.h> 38d5ac70f0Sopenharmony_ci#include <poll.h> 39d5ac70f0Sopenharmony_ci#include <pthread.h> 40d5ac70f0Sopenharmony_ci 41d5ac70f0Sopenharmony_ci#ifndef PIC 42d5ac70f0Sopenharmony_ci/* entry for static linking */ 43d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_share = ""; 44d5ac70f0Sopenharmony_ci#endif 45d5ac70f0Sopenharmony_ci 46d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 47d5ac70f0Sopenharmony_ci 48d5ac70f0Sopenharmony_cistatic LIST_HEAD(snd_pcm_share_slaves); 49d5ac70f0Sopenharmony_cistatic pthread_mutex_t snd_pcm_share_slaves_mutex = PTHREAD_MUTEX_INITIALIZER; 50d5ac70f0Sopenharmony_ci 51d5ac70f0Sopenharmony_ci#ifdef MUTEX_DEBUG 52d5ac70f0Sopenharmony_ci#define Pthread_mutex_lock(mutex) \ 53d5ac70f0Sopenharmony_cichar *snd_pcm_share_slaves_mutex_holder; 54d5ac70f0Sopenharmony_cido { \ 55d5ac70f0Sopenharmony_ci int err = pthread_mutex_trylock(mutex); \ 56d5ac70f0Sopenharmony_ci if (err < 0) { \ 57d5ac70f0Sopenharmony_ci fprintf(stderr, "lock " #mutex " is busy (%s): waiting in " __func__ "\n", *(mutex##_holder)); \ 58d5ac70f0Sopenharmony_ci pthread_mutex_lock(mutex); \ 59d5ac70f0Sopenharmony_ci fprintf(stderr, "... got\n"); \ 60d5ac70f0Sopenharmony_ci } \ 61d5ac70f0Sopenharmony_ci *(mutex##_holder) = __func__; \ 62d5ac70f0Sopenharmony_ci} while (0) 63d5ac70f0Sopenharmony_ci 64d5ac70f0Sopenharmony_ci#define Pthread_mutex_unlock(mutex) \ 65d5ac70f0Sopenharmony_cido { \ 66d5ac70f0Sopenharmony_ci *(mutex##_holder) = 0; \ 67d5ac70f0Sopenharmony_ci pthread_mutex_unlock(mutex); \ 68d5ac70f0Sopenharmony_ci} while (0) 69d5ac70f0Sopenharmony_ci#else 70d5ac70f0Sopenharmony_ci#define Pthread_mutex_lock(mutex) pthread_mutex_lock(mutex) 71d5ac70f0Sopenharmony_ci#define Pthread_mutex_unlock(mutex) pthread_mutex_unlock(mutex) 72d5ac70f0Sopenharmony_ci#endif 73d5ac70f0Sopenharmony_ci 74d5ac70f0Sopenharmony_citypedef struct { 75d5ac70f0Sopenharmony_ci struct list_head clients; 76d5ac70f0Sopenharmony_ci struct list_head list; 77d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 78d5ac70f0Sopenharmony_ci snd_pcm_format_t format; 79d5ac70f0Sopenharmony_ci int rate; 80d5ac70f0Sopenharmony_ci unsigned int channels; 81d5ac70f0Sopenharmony_ci snd_pcm_sframes_t period_time; 82d5ac70f0Sopenharmony_ci snd_pcm_sframes_t buffer_time; 83d5ac70f0Sopenharmony_ci unsigned int open_count; 84d5ac70f0Sopenharmony_ci unsigned int setup_count; 85d5ac70f0Sopenharmony_ci unsigned int prepared_count; 86d5ac70f0Sopenharmony_ci unsigned int running_count; 87d5ac70f0Sopenharmony_ci snd_pcm_uframes_t safety_threshold; 88d5ac70f0Sopenharmony_ci snd_pcm_uframes_t silence_frames; 89d5ac70f0Sopenharmony_ci snd_pcm_sw_params_t sw_params; 90d5ac70f0Sopenharmony_ci snd_pcm_uframes_t hw_ptr; 91d5ac70f0Sopenharmony_ci int poll[2]; 92d5ac70f0Sopenharmony_ci int polling; 93d5ac70f0Sopenharmony_ci pthread_t thread; 94d5ac70f0Sopenharmony_ci pthread_mutex_t mutex; 95d5ac70f0Sopenharmony_ci#ifdef MUTEX_DEBUG 96d5ac70f0Sopenharmony_ci char *mutex_holder; 97d5ac70f0Sopenharmony_ci#endif 98d5ac70f0Sopenharmony_ci pthread_cond_t poll_cond; 99d5ac70f0Sopenharmony_ci} snd_pcm_share_slave_t; 100d5ac70f0Sopenharmony_ci 101d5ac70f0Sopenharmony_citypedef struct { 102d5ac70f0Sopenharmony_ci struct list_head list; 103d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 104d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave; 105d5ac70f0Sopenharmony_ci unsigned int channels; 106d5ac70f0Sopenharmony_ci unsigned int *slave_channels; 107d5ac70f0Sopenharmony_ci int drain_silenced; 108d5ac70f0Sopenharmony_ci snd_htimestamp_t trigger_tstamp; 109d5ac70f0Sopenharmony_ci snd_pcm_state_t state; 110d5ac70f0Sopenharmony_ci snd_pcm_uframes_t hw_ptr; 111d5ac70f0Sopenharmony_ci snd_pcm_uframes_t appl_ptr; 112d5ac70f0Sopenharmony_ci int ready; 113d5ac70f0Sopenharmony_ci int client_socket; 114d5ac70f0Sopenharmony_ci int slave_socket; 115d5ac70f0Sopenharmony_ci} snd_pcm_share_t; 116d5ac70f0Sopenharmony_ci 117d5ac70f0Sopenharmony_ci#endif /* DOC_HIDDEN */ 118d5ac70f0Sopenharmony_ci 119d5ac70f0Sopenharmony_cistatic void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state); 120d5ac70f0Sopenharmony_ci 121d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t snd_pcm_share_slave_avail(snd_pcm_share_slave_t *slave) 122d5ac70f0Sopenharmony_ci{ 123d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail; 124d5ac70f0Sopenharmony_ci snd_pcm_t *pcm = slave->pcm; 125d5ac70f0Sopenharmony_ci avail = slave->hw_ptr - *pcm->appl.ptr; 126d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) 127d5ac70f0Sopenharmony_ci avail += pcm->buffer_size; 128d5ac70f0Sopenharmony_ci if (avail < 0) 129d5ac70f0Sopenharmony_ci avail += pcm->boundary; 130d5ac70f0Sopenharmony_ci else if ((snd_pcm_uframes_t) avail >= pcm->boundary) 131d5ac70f0Sopenharmony_ci avail -= pcm->boundary; 132d5ac70f0Sopenharmony_ci return avail; 133d5ac70f0Sopenharmony_ci} 134d5ac70f0Sopenharmony_ci 135d5ac70f0Sopenharmony_ci/* Warning: take the mutex before to call this */ 136d5ac70f0Sopenharmony_ci/* Return number of frames to mmap_commit the slave */ 137d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t _snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave) 138d5ac70f0Sopenharmony_ci{ 139d5ac70f0Sopenharmony_ci struct list_head *i; 140d5ac70f0Sopenharmony_ci snd_pcm_uframes_t buffer_size; 141d5ac70f0Sopenharmony_ci snd_pcm_sframes_t frames, safety_frames; 142d5ac70f0Sopenharmony_ci snd_pcm_sframes_t min_frames, max_frames; 143d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail, slave_avail; 144d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_hw_avail; 145d5ac70f0Sopenharmony_ci slave_avail = snd_pcm_share_slave_avail(slave); 146d5ac70f0Sopenharmony_ci buffer_size = slave->pcm->buffer_size; 147d5ac70f0Sopenharmony_ci min_frames = slave_avail; 148d5ac70f0Sopenharmony_ci max_frames = 0; 149d5ac70f0Sopenharmony_ci list_for_each(i, &slave->clients) { 150d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list); 151d5ac70f0Sopenharmony_ci snd_pcm_t *pcm = share->pcm; 152d5ac70f0Sopenharmony_ci switch (share->state) { 153d5ac70f0Sopenharmony_ci case SND_PCM_STATE_RUNNING: 154d5ac70f0Sopenharmony_ci break; 155d5ac70f0Sopenharmony_ci case SND_PCM_STATE_DRAINING: 156d5ac70f0Sopenharmony_ci if (pcm->stream != SND_PCM_STREAM_PLAYBACK) 157d5ac70f0Sopenharmony_ci continue; 158d5ac70f0Sopenharmony_ci break; 159d5ac70f0Sopenharmony_ci default: 160d5ac70f0Sopenharmony_ci continue; 161d5ac70f0Sopenharmony_ci } 162d5ac70f0Sopenharmony_ci avail = snd_pcm_mmap_avail(pcm); 163d5ac70f0Sopenharmony_ci frames = slave_avail - avail; 164d5ac70f0Sopenharmony_ci if (frames > max_frames) 165d5ac70f0Sopenharmony_ci max_frames = frames; 166d5ac70f0Sopenharmony_ci if (share->state != SND_PCM_STATE_RUNNING) 167d5ac70f0Sopenharmony_ci continue; 168d5ac70f0Sopenharmony_ci if (frames < min_frames) 169d5ac70f0Sopenharmony_ci min_frames = frames; 170d5ac70f0Sopenharmony_ci } 171d5ac70f0Sopenharmony_ci if (max_frames == 0) 172d5ac70f0Sopenharmony_ci return 0; 173d5ac70f0Sopenharmony_ci frames = min_frames; 174d5ac70f0Sopenharmony_ci /* Slave xrun prevention */ 175d5ac70f0Sopenharmony_ci slave_hw_avail = buffer_size - slave_avail; 176d5ac70f0Sopenharmony_ci safety_frames = slave->safety_threshold - slave_hw_avail; 177d5ac70f0Sopenharmony_ci if (safety_frames > 0 && 178d5ac70f0Sopenharmony_ci frames < safety_frames) { 179d5ac70f0Sopenharmony_ci /* Avoid to pass over the last */ 180d5ac70f0Sopenharmony_ci if (max_frames < safety_frames) 181d5ac70f0Sopenharmony_ci frames = max_frames; 182d5ac70f0Sopenharmony_ci else 183d5ac70f0Sopenharmony_ci frames = safety_frames; 184d5ac70f0Sopenharmony_ci } 185d5ac70f0Sopenharmony_ci if (frames < 0) 186d5ac70f0Sopenharmony_ci return 0; 187d5ac70f0Sopenharmony_ci return frames; 188d5ac70f0Sopenharmony_ci} 189d5ac70f0Sopenharmony_ci 190d5ac70f0Sopenharmony_ci 191d5ac70f0Sopenharmony_ci/* 192d5ac70f0Sopenharmony_ci - stop PCM on xrun 193d5ac70f0Sopenharmony_ci - update poll status 194d5ac70f0Sopenharmony_ci - draining silencing 195d5ac70f0Sopenharmony_ci - return distance in frames to next event 196d5ac70f0Sopenharmony_ci*/ 197d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t _snd_pcm_share_missing(snd_pcm_t *pcm) 198d5ac70f0Sopenharmony_ci{ 199d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 200d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 201d5ac70f0Sopenharmony_ci snd_pcm_t *spcm = slave->pcm; 202d5ac70f0Sopenharmony_ci snd_pcm_uframes_t buffer_size = spcm->buffer_size; 203d5ac70f0Sopenharmony_ci int ready = 1, running = 0; 204d5ac70f0Sopenharmony_ci snd_pcm_uframes_t avail = 0, slave_avail; 205d5ac70f0Sopenharmony_ci snd_pcm_sframes_t hw_avail; 206d5ac70f0Sopenharmony_ci snd_pcm_uframes_t missing = INT_MAX; 207d5ac70f0Sopenharmony_ci snd_pcm_sframes_t ready_missing; 208d5ac70f0Sopenharmony_ci ssize_t s; 209d5ac70f0Sopenharmony_ci // printf("state=%s hw_ptr=%ld appl_ptr=%ld slave appl_ptr=%ld safety=%ld silence=%ld\n", snd_pcm_state_name(share->state), slave->hw_ptr, share->appl_ptr, *slave->pcm->appl_ptr, slave->safety_threshold, slave->silence_frames); 210d5ac70f0Sopenharmony_ci switch (share->state) { 211d5ac70f0Sopenharmony_ci case SND_PCM_STATE_RUNNING: 212d5ac70f0Sopenharmony_ci break; 213d5ac70f0Sopenharmony_ci case SND_PCM_STATE_DRAINING: 214d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) 215d5ac70f0Sopenharmony_ci break; 216d5ac70f0Sopenharmony_ci /* Fall through */ 217d5ac70f0Sopenharmony_ci default: 218d5ac70f0Sopenharmony_ci return INT_MAX; 219d5ac70f0Sopenharmony_ci } 220d5ac70f0Sopenharmony_ci share->hw_ptr = slave->hw_ptr; 221d5ac70f0Sopenharmony_ci avail = snd_pcm_mmap_avail(pcm); 222d5ac70f0Sopenharmony_ci if (avail >= pcm->stop_threshold) { 223d5ac70f0Sopenharmony_ci _snd_pcm_share_stop(pcm, share->state == SND_PCM_STATE_DRAINING ? SND_PCM_STATE_SETUP : SND_PCM_STATE_XRUN); 224d5ac70f0Sopenharmony_ci goto update_poll; 225d5ac70f0Sopenharmony_ci } 226d5ac70f0Sopenharmony_ci hw_avail = buffer_size - avail; 227d5ac70f0Sopenharmony_ci slave_avail = snd_pcm_share_slave_avail(slave); 228d5ac70f0Sopenharmony_ci if (avail < slave_avail) { 229d5ac70f0Sopenharmony_ci /* Some frames need still to be transferred */ 230d5ac70f0Sopenharmony_ci snd_pcm_sframes_t slave_hw_avail = buffer_size - slave_avail; 231d5ac70f0Sopenharmony_ci snd_pcm_sframes_t safety_missing = slave_hw_avail - slave->safety_threshold; 232d5ac70f0Sopenharmony_ci if (safety_missing < 0) { 233d5ac70f0Sopenharmony_ci snd_pcm_sframes_t err; 234d5ac70f0Sopenharmony_ci snd_pcm_sframes_t frames = slave_avail - avail; 235d5ac70f0Sopenharmony_ci if (-safety_missing <= frames) { 236d5ac70f0Sopenharmony_ci frames = -safety_missing; 237d5ac70f0Sopenharmony_ci missing = 1; 238d5ac70f0Sopenharmony_ci } 239d5ac70f0Sopenharmony_ci err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames); 240d5ac70f0Sopenharmony_ci if (err < 0) { 241d5ac70f0Sopenharmony_ci SYSMSG("snd_pcm_mmap_commit error"); 242d5ac70f0Sopenharmony_ci return INT_MAX; 243d5ac70f0Sopenharmony_ci } 244d5ac70f0Sopenharmony_ci if (err != frames) 245d5ac70f0Sopenharmony_ci SYSMSG("commit returns %ld for size %ld", err, frames); 246d5ac70f0Sopenharmony_ci slave_avail -= err; 247d5ac70f0Sopenharmony_ci } else { 248d5ac70f0Sopenharmony_ci if (safety_missing == 0) 249d5ac70f0Sopenharmony_ci missing = 1; 250d5ac70f0Sopenharmony_ci else 251d5ac70f0Sopenharmony_ci missing = safety_missing; 252d5ac70f0Sopenharmony_ci } 253d5ac70f0Sopenharmony_ci } 254d5ac70f0Sopenharmony_ci switch (share->state) { 255d5ac70f0Sopenharmony_ci case SND_PCM_STATE_DRAINING: 256d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 257d5ac70f0Sopenharmony_ci if (hw_avail <= 0) { 258d5ac70f0Sopenharmony_ci _snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP); 259d5ac70f0Sopenharmony_ci break; 260d5ac70f0Sopenharmony_ci } 261d5ac70f0Sopenharmony_ci if ((snd_pcm_uframes_t)hw_avail < missing) 262d5ac70f0Sopenharmony_ci missing = hw_avail; 263d5ac70f0Sopenharmony_ci running = 1; 264d5ac70f0Sopenharmony_ci ready = 0; 265d5ac70f0Sopenharmony_ci } 266d5ac70f0Sopenharmony_ci break; 267d5ac70f0Sopenharmony_ci case SND_PCM_STATE_RUNNING: 268d5ac70f0Sopenharmony_ci if (avail >= pcm->stop_threshold) { 269d5ac70f0Sopenharmony_ci _snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN); 270d5ac70f0Sopenharmony_ci break; 271d5ac70f0Sopenharmony_ci } else { 272d5ac70f0Sopenharmony_ci snd_pcm_uframes_t xrun_missing = pcm->stop_threshold - avail; 273d5ac70f0Sopenharmony_ci if (missing > xrun_missing) 274d5ac70f0Sopenharmony_ci missing = xrun_missing; 275d5ac70f0Sopenharmony_ci } 276d5ac70f0Sopenharmony_ci ready_missing = pcm->avail_min - avail; 277d5ac70f0Sopenharmony_ci if (ready_missing > 0) { 278d5ac70f0Sopenharmony_ci ready = 0; 279d5ac70f0Sopenharmony_ci if (missing > (snd_pcm_uframes_t)ready_missing) 280d5ac70f0Sopenharmony_ci missing = ready_missing; 281d5ac70f0Sopenharmony_ci } 282d5ac70f0Sopenharmony_ci running = 1; 283d5ac70f0Sopenharmony_ci break; 284d5ac70f0Sopenharmony_ci default: 285d5ac70f0Sopenharmony_ci SNDERR("invalid shared PCM state %d", share->state); 286d5ac70f0Sopenharmony_ci return INT_MAX; 287d5ac70f0Sopenharmony_ci } 288d5ac70f0Sopenharmony_ci 289d5ac70f0Sopenharmony_ci update_poll: 290d5ac70f0Sopenharmony_ci if (ready != share->ready) { 291d5ac70f0Sopenharmony_ci char buf[1]; 292d5ac70f0Sopenharmony_ci while (1) { 293d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 294d5ac70f0Sopenharmony_ci if (ready) 295d5ac70f0Sopenharmony_ci s = read(share->slave_socket, buf, 1); 296d5ac70f0Sopenharmony_ci else 297d5ac70f0Sopenharmony_ci s = write(share->client_socket, buf, 1); 298d5ac70f0Sopenharmony_ci } else { 299d5ac70f0Sopenharmony_ci if (ready) 300d5ac70f0Sopenharmony_ci s = write(share->slave_socket, buf, 1); 301d5ac70f0Sopenharmony_ci else 302d5ac70f0Sopenharmony_ci s = read(share->client_socket, buf, 1); 303d5ac70f0Sopenharmony_ci } 304d5ac70f0Sopenharmony_ci if (s < 0) { 305d5ac70f0Sopenharmony_ci if (errno == EINTR) 306d5ac70f0Sopenharmony_ci continue; 307d5ac70f0Sopenharmony_ci return INT_MAX; 308d5ac70f0Sopenharmony_ci } 309d5ac70f0Sopenharmony_ci break; 310d5ac70f0Sopenharmony_ci } 311d5ac70f0Sopenharmony_ci share->ready = ready; 312d5ac70f0Sopenharmony_ci } 313d5ac70f0Sopenharmony_ci if (!running) 314d5ac70f0Sopenharmony_ci return INT_MAX; 315d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK && 316d5ac70f0Sopenharmony_ci share->state == SND_PCM_STATE_DRAINING && 317d5ac70f0Sopenharmony_ci !share->drain_silenced) { 318d5ac70f0Sopenharmony_ci /* drain silencing */ 319d5ac70f0Sopenharmony_ci if (avail >= slave->silence_frames) { 320d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset = share->appl_ptr % buffer_size; 321d5ac70f0Sopenharmony_ci snd_pcm_uframes_t xfer = 0; 322d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size = slave->silence_frames; 323d5ac70f0Sopenharmony_ci while (xfer < size) { 324d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames = size - xfer; 325d5ac70f0Sopenharmony_ci snd_pcm_uframes_t cont = buffer_size - offset; 326d5ac70f0Sopenharmony_ci if (cont < frames) 327d5ac70f0Sopenharmony_ci frames = cont; 328d5ac70f0Sopenharmony_ci snd_pcm_areas_silence(pcm->running_areas, offset, pcm->channels, frames, pcm->format); 329d5ac70f0Sopenharmony_ci offset += frames; 330d5ac70f0Sopenharmony_ci if (offset >= buffer_size) 331d5ac70f0Sopenharmony_ci offset = 0; 332d5ac70f0Sopenharmony_ci xfer += frames; 333d5ac70f0Sopenharmony_ci } 334d5ac70f0Sopenharmony_ci share->drain_silenced = 1; 335d5ac70f0Sopenharmony_ci } else { 336d5ac70f0Sopenharmony_ci snd_pcm_uframes_t silence_missing; 337d5ac70f0Sopenharmony_ci silence_missing = slave->silence_frames - avail; 338d5ac70f0Sopenharmony_ci if (silence_missing < missing) 339d5ac70f0Sopenharmony_ci missing = silence_missing; 340d5ac70f0Sopenharmony_ci } 341d5ac70f0Sopenharmony_ci } 342d5ac70f0Sopenharmony_ci // printf("missing=%d\n", missing); 343d5ac70f0Sopenharmony_ci return missing; 344d5ac70f0Sopenharmony_ci} 345d5ac70f0Sopenharmony_ci 346d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t _snd_pcm_share_slave_missing(snd_pcm_share_slave_t *slave) 347d5ac70f0Sopenharmony_ci{ 348d5ac70f0Sopenharmony_ci snd_pcm_uframes_t missing = INT_MAX; 349d5ac70f0Sopenharmony_ci struct list_head *i; 350d5ac70f0Sopenharmony_ci /* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(slave->pcm); 351d5ac70f0Sopenharmony_ci slave->hw_ptr = *slave->pcm->hw.ptr; 352d5ac70f0Sopenharmony_ci list_for_each(i, &slave->clients) { 353d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list); 354d5ac70f0Sopenharmony_ci snd_pcm_t *pcm = share->pcm; 355d5ac70f0Sopenharmony_ci snd_pcm_uframes_t m = _snd_pcm_share_missing(pcm); 356d5ac70f0Sopenharmony_ci if (m < missing) 357d5ac70f0Sopenharmony_ci missing = m; 358d5ac70f0Sopenharmony_ci } 359d5ac70f0Sopenharmony_ci return missing; 360d5ac70f0Sopenharmony_ci} 361d5ac70f0Sopenharmony_ci 362d5ac70f0Sopenharmony_cistatic void *snd_pcm_share_thread(void *data) 363d5ac70f0Sopenharmony_ci{ 364d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = data; 365d5ac70f0Sopenharmony_ci snd_pcm_t *spcm = slave->pcm; 366d5ac70f0Sopenharmony_ci struct pollfd pfd[2]; 367d5ac70f0Sopenharmony_ci int err; 368d5ac70f0Sopenharmony_ci 369d5ac70f0Sopenharmony_ci pfd[0].fd = slave->poll[0]; 370d5ac70f0Sopenharmony_ci pfd[0].events = POLLIN; 371d5ac70f0Sopenharmony_ci err = snd_pcm_poll_descriptors(spcm, &pfd[1], 1); 372d5ac70f0Sopenharmony_ci if (err != 1) { 373d5ac70f0Sopenharmony_ci SNDERR("invalid poll descriptors %d", err); 374d5ac70f0Sopenharmony_ci return NULL; 375d5ac70f0Sopenharmony_ci } 376d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 377d5ac70f0Sopenharmony_ci err = pipe(slave->poll); 378d5ac70f0Sopenharmony_ci if (err < 0) { 379d5ac70f0Sopenharmony_ci SYSERR("can't create a pipe"); 380d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 381d5ac70f0Sopenharmony_ci return NULL; 382d5ac70f0Sopenharmony_ci } 383d5ac70f0Sopenharmony_ci while (slave->open_count > 0) { 384d5ac70f0Sopenharmony_ci snd_pcm_uframes_t missing; 385d5ac70f0Sopenharmony_ci // printf("begin min_missing\n"); 386d5ac70f0Sopenharmony_ci missing = _snd_pcm_share_slave_missing(slave); 387d5ac70f0Sopenharmony_ci // printf("min_missing=%ld\n", missing); 388d5ac70f0Sopenharmony_ci if (missing < INT_MAX) { 389d5ac70f0Sopenharmony_ci snd_pcm_uframes_t hw_ptr; 390d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail_min; 391d5ac70f0Sopenharmony_ci hw_ptr = slave->hw_ptr + missing; 392d5ac70f0Sopenharmony_ci hw_ptr += spcm->period_size - 1; 393d5ac70f0Sopenharmony_ci if (hw_ptr >= spcm->boundary) 394d5ac70f0Sopenharmony_ci hw_ptr -= spcm->boundary; 395d5ac70f0Sopenharmony_ci hw_ptr -= hw_ptr % spcm->period_size; 396d5ac70f0Sopenharmony_ci avail_min = hw_ptr - *spcm->appl.ptr; 397d5ac70f0Sopenharmony_ci if (spcm->stream == SND_PCM_STREAM_PLAYBACK) 398d5ac70f0Sopenharmony_ci avail_min += spcm->buffer_size; 399d5ac70f0Sopenharmony_ci if (avail_min < 0) 400d5ac70f0Sopenharmony_ci avail_min += spcm->boundary; 401d5ac70f0Sopenharmony_ci // printf("avail_min=%d\n", avail_min); 402d5ac70f0Sopenharmony_ci if ((snd_pcm_uframes_t)avail_min != spcm->avail_min) { 403d5ac70f0Sopenharmony_ci snd_pcm_sw_params_set_avail_min(spcm, &slave->sw_params, avail_min); 404d5ac70f0Sopenharmony_ci err = snd_pcm_sw_params(spcm, &slave->sw_params); 405d5ac70f0Sopenharmony_ci if (err < 0) { 406d5ac70f0Sopenharmony_ci SYSERR("snd_pcm_sw_params error"); 407d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 408d5ac70f0Sopenharmony_ci return NULL; 409d5ac70f0Sopenharmony_ci } 410d5ac70f0Sopenharmony_ci } 411d5ac70f0Sopenharmony_ci slave->polling = 1; 412d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 413d5ac70f0Sopenharmony_ci err = poll(pfd, 2, -1); 414d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 415d5ac70f0Sopenharmony_ci if (pfd[0].revents & POLLIN) { 416d5ac70f0Sopenharmony_ci char buf[1]; 417d5ac70f0Sopenharmony_ci read(pfd[0].fd, buf, 1); 418d5ac70f0Sopenharmony_ci } 419d5ac70f0Sopenharmony_ci } else { 420d5ac70f0Sopenharmony_ci slave->polling = 0; 421d5ac70f0Sopenharmony_ci pthread_cond_wait(&slave->poll_cond, &slave->mutex); 422d5ac70f0Sopenharmony_ci } 423d5ac70f0Sopenharmony_ci } 424d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 425d5ac70f0Sopenharmony_ci return NULL; 426d5ac70f0Sopenharmony_ci} 427d5ac70f0Sopenharmony_ci 428d5ac70f0Sopenharmony_cistatic void _snd_pcm_share_update(snd_pcm_t *pcm) 429d5ac70f0Sopenharmony_ci{ 430d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 431d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 432d5ac70f0Sopenharmony_ci snd_pcm_t *spcm = slave->pcm; 433d5ac70f0Sopenharmony_ci snd_pcm_uframes_t missing; 434d5ac70f0Sopenharmony_ci /* snd_pcm_sframes_t avail = */ snd_pcm_avail_update(spcm); 435d5ac70f0Sopenharmony_ci slave->hw_ptr = *slave->pcm->hw.ptr; 436d5ac70f0Sopenharmony_ci missing = _snd_pcm_share_missing(pcm); 437d5ac70f0Sopenharmony_ci // printf("missing %ld\n", missing); 438d5ac70f0Sopenharmony_ci if (!slave->polling) { 439d5ac70f0Sopenharmony_ci pthread_cond_signal(&slave->poll_cond); 440d5ac70f0Sopenharmony_ci return; 441d5ac70f0Sopenharmony_ci } 442d5ac70f0Sopenharmony_ci if (missing < INT_MAX) { 443d5ac70f0Sopenharmony_ci snd_pcm_uframes_t hw_ptr; 444d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail_min; 445d5ac70f0Sopenharmony_ci hw_ptr = slave->hw_ptr + missing; 446d5ac70f0Sopenharmony_ci hw_ptr += spcm->period_size - 1; 447d5ac70f0Sopenharmony_ci if (hw_ptr >= spcm->boundary) 448d5ac70f0Sopenharmony_ci hw_ptr -= spcm->boundary; 449d5ac70f0Sopenharmony_ci hw_ptr -= hw_ptr % spcm->period_size; 450d5ac70f0Sopenharmony_ci avail_min = hw_ptr - *spcm->appl.ptr; 451d5ac70f0Sopenharmony_ci if (spcm->stream == SND_PCM_STREAM_PLAYBACK) 452d5ac70f0Sopenharmony_ci avail_min += spcm->buffer_size; 453d5ac70f0Sopenharmony_ci if (avail_min < 0) 454d5ac70f0Sopenharmony_ci avail_min += spcm->boundary; 455d5ac70f0Sopenharmony_ci if ((snd_pcm_uframes_t)avail_min < spcm->avail_min) { 456d5ac70f0Sopenharmony_ci int err; 457d5ac70f0Sopenharmony_ci snd_pcm_sw_params_set_avail_min(spcm, &slave->sw_params, avail_min); 458d5ac70f0Sopenharmony_ci err = snd_pcm_sw_params(spcm, &slave->sw_params); 459d5ac70f0Sopenharmony_ci if (err < 0) { 460d5ac70f0Sopenharmony_ci SYSERR("snd_pcm_sw_params error"); 461d5ac70f0Sopenharmony_ci return; 462d5ac70f0Sopenharmony_ci } 463d5ac70f0Sopenharmony_ci } 464d5ac70f0Sopenharmony_ci } 465d5ac70f0Sopenharmony_ci} 466d5ac70f0Sopenharmony_ci 467d5ac70f0Sopenharmony_cistatic int snd_pcm_share_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) 468d5ac70f0Sopenharmony_ci{ 469d5ac70f0Sopenharmony_ci return 0; 470d5ac70f0Sopenharmony_ci} 471d5ac70f0Sopenharmony_ci 472d5ac70f0Sopenharmony_cistatic int snd_pcm_share_async(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int sig ATTRIBUTE_UNUSED, pid_t pid ATTRIBUTE_UNUSED) 473d5ac70f0Sopenharmony_ci{ 474d5ac70f0Sopenharmony_ci return -ENOSYS; 475d5ac70f0Sopenharmony_ci} 476d5ac70f0Sopenharmony_ci 477d5ac70f0Sopenharmony_cistatic int snd_pcm_share_info(snd_pcm_t *pcm, snd_pcm_info_t *info) 478d5ac70f0Sopenharmony_ci{ 479d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 480d5ac70f0Sopenharmony_ci return snd_pcm_info(share->slave->pcm, info); 481d5ac70f0Sopenharmony_ci} 482d5ac70f0Sopenharmony_ci 483d5ac70f0Sopenharmony_cistatic int snd_pcm_share_hw_refine_cprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 484d5ac70f0Sopenharmony_ci{ 485d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 486d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 487d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t access_mask; 488d5ac70f0Sopenharmony_ci int err; 489d5ac70f0Sopenharmony_ci snd_pcm_access_mask_any(&access_mask); 490d5ac70f0Sopenharmony_ci snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); 491d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, 492d5ac70f0Sopenharmony_ci &access_mask); 493d5ac70f0Sopenharmony_ci if (err < 0) 494d5ac70f0Sopenharmony_ci return err; 495d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_CHANNELS, 496d5ac70f0Sopenharmony_ci share->channels, 0); 497d5ac70f0Sopenharmony_ci if (err < 0) 498d5ac70f0Sopenharmony_ci return err; 499d5ac70f0Sopenharmony_ci if (slave->format != SND_PCM_FORMAT_UNKNOWN) { 500d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_set_format(params, slave->format); 501d5ac70f0Sopenharmony_ci if (err < 0) 502d5ac70f0Sopenharmony_ci return err; 503d5ac70f0Sopenharmony_ci } 504d5ac70f0Sopenharmony_ci 505d5ac70f0Sopenharmony_ci if (slave->rate >= 0) { 506d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_RATE, 507d5ac70f0Sopenharmony_ci slave->rate, 0); 508d5ac70f0Sopenharmony_ci if (err < 0) 509d5ac70f0Sopenharmony_ci return err; 510d5ac70f0Sopenharmony_ci } 511d5ac70f0Sopenharmony_ci if (slave->period_time >= 0) { 512d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_PERIOD_TIME, 513d5ac70f0Sopenharmony_ci slave->period_time, 0); 514d5ac70f0Sopenharmony_ci if (err < 0) 515d5ac70f0Sopenharmony_ci return err; 516d5ac70f0Sopenharmony_ci } 517d5ac70f0Sopenharmony_ci if (slave->buffer_time >= 0) { 518d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_TIME, 519d5ac70f0Sopenharmony_ci slave->buffer_time, 0); 520d5ac70f0Sopenharmony_ci if (err < 0) 521d5ac70f0Sopenharmony_ci return err; 522d5ac70f0Sopenharmony_ci } 523d5ac70f0Sopenharmony_ci params->info |= SND_PCM_INFO_DOUBLE; 524d5ac70f0Sopenharmony_ci return 0; 525d5ac70f0Sopenharmony_ci} 526d5ac70f0Sopenharmony_ci 527d5ac70f0Sopenharmony_cistatic int snd_pcm_share_hw_refine_sprepare(snd_pcm_t *pcm, snd_pcm_hw_params_t *sparams) 528d5ac70f0Sopenharmony_ci{ 529d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 530d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 531d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; 532d5ac70f0Sopenharmony_ci _snd_pcm_hw_params_any(sparams); 533d5ac70f0Sopenharmony_ci _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, 534d5ac70f0Sopenharmony_ci &saccess_mask); 535d5ac70f0Sopenharmony_ci _snd_pcm_hw_param_set(sparams, SND_PCM_HW_PARAM_CHANNELS, 536d5ac70f0Sopenharmony_ci slave->channels, 0); 537d5ac70f0Sopenharmony_ci return 0; 538d5ac70f0Sopenharmony_ci} 539d5ac70f0Sopenharmony_ci 540d5ac70f0Sopenharmony_cistatic int snd_pcm_share_hw_refine_schange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, 541d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams) 542d5ac70f0Sopenharmony_ci{ 543d5ac70f0Sopenharmony_ci int err; 544d5ac70f0Sopenharmony_ci unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | 545d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_SUBFORMAT | 546d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_RATE | 547d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_SIZE | 548d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_TIME | 549d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_SIZE | 550d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_TIME | 551d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIODS); 552d5ac70f0Sopenharmony_ci const snd_pcm_access_mask_t *access_mask = snd_pcm_hw_param_get_mask(params, SND_PCM_HW_PARAM_ACCESS); 553d5ac70f0Sopenharmony_ci if (!snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED) && 554d5ac70f0Sopenharmony_ci !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED) && 555d5ac70f0Sopenharmony_ci !snd_pcm_access_mask_test(access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) { 556d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t saccess_mask; 557d5ac70f0Sopenharmony_ci snd_pcm_access_mask_any(&saccess_mask); 558d5ac70f0Sopenharmony_ci snd_pcm_access_mask_reset(&saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); 559d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, 560d5ac70f0Sopenharmony_ci &saccess_mask); 561d5ac70f0Sopenharmony_ci if (err < 0) 562d5ac70f0Sopenharmony_ci return err; 563d5ac70f0Sopenharmony_ci } 564d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_refine(sparams, links, params); 565d5ac70f0Sopenharmony_ci if (err < 0) 566d5ac70f0Sopenharmony_ci return err; 567d5ac70f0Sopenharmony_ci return 0; 568d5ac70f0Sopenharmony_ci} 569d5ac70f0Sopenharmony_ci 570d5ac70f0Sopenharmony_cistatic int snd_pcm_share_hw_refine_cchange(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t *params, 571d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams) 572d5ac70f0Sopenharmony_ci{ 573d5ac70f0Sopenharmony_ci int err; 574d5ac70f0Sopenharmony_ci unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | 575d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_SUBFORMAT | 576d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_RATE | 577d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_SIZE | 578d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_TIME | 579d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_SIZE | 580d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_TIME | 581d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIODS); 582d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t access_mask; 583d5ac70f0Sopenharmony_ci const snd_pcm_access_mask_t *saccess_mask = snd_pcm_hw_param_get_mask(sparams, SND_PCM_HW_PARAM_ACCESS); 584d5ac70f0Sopenharmony_ci snd_pcm_access_mask_any(&access_mask); 585d5ac70f0Sopenharmony_ci snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); 586d5ac70f0Sopenharmony_ci if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) 587d5ac70f0Sopenharmony_ci snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); 588d5ac70f0Sopenharmony_ci if (!snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_COMPLEX) && 589d5ac70f0Sopenharmony_ci !snd_pcm_access_mask_test(saccess_mask, SND_PCM_ACCESS_MMAP_INTERLEAVED)) 590d5ac70f0Sopenharmony_ci snd_pcm_access_mask_reset(&access_mask, SND_PCM_ACCESS_MMAP_COMPLEX); 591d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, 592d5ac70f0Sopenharmony_ci &access_mask); 593d5ac70f0Sopenharmony_ci if (err < 0) 594d5ac70f0Sopenharmony_ci return err; 595d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_refine(params, links, sparams); 596d5ac70f0Sopenharmony_ci if (err < 0) 597d5ac70f0Sopenharmony_ci return err; 598d5ac70f0Sopenharmony_ci return 0; 599d5ac70f0Sopenharmony_ci} 600d5ac70f0Sopenharmony_ci 601d5ac70f0Sopenharmony_cistatic int snd_pcm_share_hw_refine_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 602d5ac70f0Sopenharmony_ci{ 603d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 604d5ac70f0Sopenharmony_ci return snd_pcm_hw_refine(share->slave->pcm, params); 605d5ac70f0Sopenharmony_ci} 606d5ac70f0Sopenharmony_ci 607d5ac70f0Sopenharmony_cistatic int snd_pcm_share_hw_params_slave(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 608d5ac70f0Sopenharmony_ci{ 609d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 610d5ac70f0Sopenharmony_ci return _snd_pcm_hw_params_internal(share->slave->pcm, params); 611d5ac70f0Sopenharmony_ci} 612d5ac70f0Sopenharmony_ci 613d5ac70f0Sopenharmony_cistatic int snd_pcm_share_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 614d5ac70f0Sopenharmony_ci{ 615d5ac70f0Sopenharmony_ci return snd_pcm_hw_refine_slave(pcm, params, 616d5ac70f0Sopenharmony_ci snd_pcm_share_hw_refine_cprepare, 617d5ac70f0Sopenharmony_ci snd_pcm_share_hw_refine_cchange, 618d5ac70f0Sopenharmony_ci snd_pcm_share_hw_refine_sprepare, 619d5ac70f0Sopenharmony_ci snd_pcm_share_hw_refine_schange, 620d5ac70f0Sopenharmony_ci snd_pcm_share_hw_refine_slave); 621d5ac70f0Sopenharmony_ci} 622d5ac70f0Sopenharmony_ci 623d5ac70f0Sopenharmony_cistatic int snd_pcm_share_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 624d5ac70f0Sopenharmony_ci{ 625d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 626d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 627d5ac70f0Sopenharmony_ci snd_pcm_t *spcm = slave->pcm; 628d5ac70f0Sopenharmony_ci int err = 0; 629d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 630d5ac70f0Sopenharmony_ci if (slave->setup_count) { 631d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_set_format(params, spcm->format); 632d5ac70f0Sopenharmony_ci if (err < 0) 633d5ac70f0Sopenharmony_ci goto _err; 634d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_params_set_subformat(params, spcm->subformat); 635d5ac70f0Sopenharmony_ci if (err < 0) 636d5ac70f0Sopenharmony_ci goto _err; 637d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_RATE, 638d5ac70f0Sopenharmony_ci spcm->rate, 0, 639d5ac70f0Sopenharmony_ci spcm->rate, 1); 640d5ac70f0Sopenharmony_ci if (err < 0) 641d5ac70f0Sopenharmony_ci goto _err; 642d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_minmax(params, SND_PCM_HW_PARAM_PERIOD_TIME, 643d5ac70f0Sopenharmony_ci spcm->period_time, 0, 644d5ac70f0Sopenharmony_ci spcm->period_time, 1); 645d5ac70f0Sopenharmony_ci if (err < 0) 646d5ac70f0Sopenharmony_ci goto _err; 647d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set(params, SND_PCM_HW_PARAM_BUFFER_SIZE, 648d5ac70f0Sopenharmony_ci spcm->buffer_size, 0); 649d5ac70f0Sopenharmony_ci _err: 650d5ac70f0Sopenharmony_ci if (err < 0) { 651d5ac70f0Sopenharmony_ci SNDERR("slave is already running with incompatible setup"); 652d5ac70f0Sopenharmony_ci err = -EBUSY; 653d5ac70f0Sopenharmony_ci goto _end; 654d5ac70f0Sopenharmony_ci } 655d5ac70f0Sopenharmony_ci } else { 656d5ac70f0Sopenharmony_ci err = snd_pcm_hw_params_slave(pcm, params, 657d5ac70f0Sopenharmony_ci snd_pcm_share_hw_refine_cchange, 658d5ac70f0Sopenharmony_ci snd_pcm_share_hw_refine_sprepare, 659d5ac70f0Sopenharmony_ci snd_pcm_share_hw_refine_schange, 660d5ac70f0Sopenharmony_ci snd_pcm_share_hw_params_slave); 661d5ac70f0Sopenharmony_ci if (err < 0) 662d5ac70f0Sopenharmony_ci goto _end; 663d5ac70f0Sopenharmony_ci snd_pcm_sw_params_current(slave->pcm, &slave->sw_params); 664d5ac70f0Sopenharmony_ci /* >= 30 ms */ 665d5ac70f0Sopenharmony_ci slave->safety_threshold = slave->pcm->rate * 30 / 1000; 666d5ac70f0Sopenharmony_ci slave->safety_threshold += slave->pcm->period_size - 1; 667d5ac70f0Sopenharmony_ci slave->safety_threshold -= slave->safety_threshold % slave->pcm->period_size; 668d5ac70f0Sopenharmony_ci slave->silence_frames = slave->safety_threshold; 669d5ac70f0Sopenharmony_ci if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK) 670d5ac70f0Sopenharmony_ci snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->channels, slave->pcm->buffer_size, slave->pcm->format); 671d5ac70f0Sopenharmony_ci } 672d5ac70f0Sopenharmony_ci share->state = SND_PCM_STATE_SETUP; 673d5ac70f0Sopenharmony_ci slave->setup_count++; 674d5ac70f0Sopenharmony_ci _end: 675d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 676d5ac70f0Sopenharmony_ci return err; 677d5ac70f0Sopenharmony_ci} 678d5ac70f0Sopenharmony_ci 679d5ac70f0Sopenharmony_cistatic int snd_pcm_share_hw_free(snd_pcm_t *pcm) 680d5ac70f0Sopenharmony_ci{ 681d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 682d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 683d5ac70f0Sopenharmony_ci int err = 0; 684d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 685d5ac70f0Sopenharmony_ci slave->setup_count--; 686d5ac70f0Sopenharmony_ci if (slave->setup_count == 0) 687d5ac70f0Sopenharmony_ci err = snd_pcm_hw_free(slave->pcm); 688d5ac70f0Sopenharmony_ci share->state = SND_PCM_STATE_OPEN; 689d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 690d5ac70f0Sopenharmony_ci return err; 691d5ac70f0Sopenharmony_ci} 692d5ac70f0Sopenharmony_ci 693d5ac70f0Sopenharmony_cistatic int snd_pcm_share_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t *params ATTRIBUTE_UNUSED) 694d5ac70f0Sopenharmony_ci{ 695d5ac70f0Sopenharmony_ci return 0; 696d5ac70f0Sopenharmony_ci} 697d5ac70f0Sopenharmony_ci 698d5ac70f0Sopenharmony_cistatic int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status) 699d5ac70f0Sopenharmony_ci{ 700d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 701d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 702d5ac70f0Sopenharmony_ci int err = 0; 703d5ac70f0Sopenharmony_ci snd_pcm_sframes_t sd = 0, d = 0; 704d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 705d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 706d5ac70f0Sopenharmony_ci status->avail = snd_pcm_mmap_playback_avail(pcm); 707d5ac70f0Sopenharmony_ci if (share->state != SND_PCM_STATE_RUNNING && 708d5ac70f0Sopenharmony_ci share->state != SND_PCM_STATE_DRAINING) 709d5ac70f0Sopenharmony_ci goto _notrunning; 710d5ac70f0Sopenharmony_ci d = pcm->buffer_size - status->avail; 711d5ac70f0Sopenharmony_ci } else { 712d5ac70f0Sopenharmony_ci status->avail = snd_pcm_mmap_capture_avail(pcm); 713d5ac70f0Sopenharmony_ci if (share->state != SND_PCM_STATE_RUNNING) 714d5ac70f0Sopenharmony_ci goto _notrunning; 715d5ac70f0Sopenharmony_ci d = status->avail; 716d5ac70f0Sopenharmony_ci } 717d5ac70f0Sopenharmony_ci err = snd_pcm_delay(slave->pcm, &sd); 718d5ac70f0Sopenharmony_ci if (err < 0) 719d5ac70f0Sopenharmony_ci goto _end; 720d5ac70f0Sopenharmony_ci _notrunning: 721d5ac70f0Sopenharmony_ci status->delay = sd + d; 722d5ac70f0Sopenharmony_ci status->state = share->state; 723d5ac70f0Sopenharmony_ci status->appl_ptr = *pcm->appl.ptr; 724d5ac70f0Sopenharmony_ci status->hw_ptr = *pcm->hw.ptr; 725d5ac70f0Sopenharmony_ci status->trigger_tstamp = share->trigger_tstamp; 726d5ac70f0Sopenharmony_ci _end: 727d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 728d5ac70f0Sopenharmony_ci return err; 729d5ac70f0Sopenharmony_ci} 730d5ac70f0Sopenharmony_ci 731d5ac70f0Sopenharmony_cistatic snd_pcm_state_t snd_pcm_share_state(snd_pcm_t *pcm) 732d5ac70f0Sopenharmony_ci{ 733d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 734d5ac70f0Sopenharmony_ci return share->state; 735d5ac70f0Sopenharmony_ci} 736d5ac70f0Sopenharmony_ci 737d5ac70f0Sopenharmony_cistatic int _snd_pcm_share_hwsync(snd_pcm_t *pcm) 738d5ac70f0Sopenharmony_ci{ 739d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 740d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 741d5ac70f0Sopenharmony_ci switch (share->state) { 742d5ac70f0Sopenharmony_ci case SND_PCM_STATE_XRUN: 743d5ac70f0Sopenharmony_ci return -EPIPE; 744d5ac70f0Sopenharmony_ci default: 745d5ac70f0Sopenharmony_ci break; 746d5ac70f0Sopenharmony_ci } 747d5ac70f0Sopenharmony_ci return snd_pcm_hwsync(slave->pcm); 748d5ac70f0Sopenharmony_ci} 749d5ac70f0Sopenharmony_ci 750d5ac70f0Sopenharmony_cistatic int snd_pcm_share_hwsync(snd_pcm_t *pcm) 751d5ac70f0Sopenharmony_ci{ 752d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 753d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 754d5ac70f0Sopenharmony_ci int err; 755d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 756d5ac70f0Sopenharmony_ci err = _snd_pcm_share_hwsync(pcm); 757d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 758d5ac70f0Sopenharmony_ci return err; 759d5ac70f0Sopenharmony_ci} 760d5ac70f0Sopenharmony_ci 761d5ac70f0Sopenharmony_cistatic int _snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 762d5ac70f0Sopenharmony_ci{ 763d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 764d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 765d5ac70f0Sopenharmony_ci switch (share->state) { 766d5ac70f0Sopenharmony_ci case SND_PCM_STATE_XRUN: 767d5ac70f0Sopenharmony_ci return -EPIPE; 768d5ac70f0Sopenharmony_ci case SND_PCM_STATE_RUNNING: 769d5ac70f0Sopenharmony_ci break; 770d5ac70f0Sopenharmony_ci case SND_PCM_STATE_DRAINING: 771d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) 772d5ac70f0Sopenharmony_ci break; 773d5ac70f0Sopenharmony_ci /* Fall through */ 774d5ac70f0Sopenharmony_ci default: 775d5ac70f0Sopenharmony_ci return -EBADFD; 776d5ac70f0Sopenharmony_ci } 777d5ac70f0Sopenharmony_ci return snd_pcm_delay(slave->pcm, delayp); 778d5ac70f0Sopenharmony_ci} 779d5ac70f0Sopenharmony_ci 780d5ac70f0Sopenharmony_cistatic int snd_pcm_share_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) 781d5ac70f0Sopenharmony_ci{ 782d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 783d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 784d5ac70f0Sopenharmony_ci int err; 785d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 786d5ac70f0Sopenharmony_ci err = _snd_pcm_share_delay(pcm, delayp); 787d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 788d5ac70f0Sopenharmony_ci return err; 789d5ac70f0Sopenharmony_ci} 790d5ac70f0Sopenharmony_ci 791d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_share_avail_update(snd_pcm_t *pcm) 792d5ac70f0Sopenharmony_ci{ 793d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 794d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 795d5ac70f0Sopenharmony_ci snd_pcm_sframes_t avail; 796d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 797d5ac70f0Sopenharmony_ci if (share->state == SND_PCM_STATE_RUNNING) { 798d5ac70f0Sopenharmony_ci avail = snd_pcm_avail_update(slave->pcm); 799d5ac70f0Sopenharmony_ci if (avail < 0) { 800d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 801d5ac70f0Sopenharmony_ci return avail; 802d5ac70f0Sopenharmony_ci } 803d5ac70f0Sopenharmony_ci share->hw_ptr = *slave->pcm->hw.ptr; 804d5ac70f0Sopenharmony_ci } 805d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 806d5ac70f0Sopenharmony_ci avail = snd_pcm_mmap_avail(pcm); 807d5ac70f0Sopenharmony_ci if ((snd_pcm_uframes_t)avail > pcm->buffer_size) 808d5ac70f0Sopenharmony_ci return -EPIPE; 809d5ac70f0Sopenharmony_ci return avail; 810d5ac70f0Sopenharmony_ci} 811d5ac70f0Sopenharmony_ci 812d5ac70f0Sopenharmony_cistatic int snd_pcm_share_htimestamp(snd_pcm_t *pcm, snd_pcm_uframes_t *avail, 813d5ac70f0Sopenharmony_ci snd_htimestamp_t *tstamp) 814d5ac70f0Sopenharmony_ci{ 815d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 816d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 817d5ac70f0Sopenharmony_ci int err; 818d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 819d5ac70f0Sopenharmony_ci err = snd_pcm_htimestamp(slave->pcm, avail, tstamp); 820d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 821d5ac70f0Sopenharmony_ci return err; 822d5ac70f0Sopenharmony_ci} 823d5ac70f0Sopenharmony_ci 824d5ac70f0Sopenharmony_ci/* Call it with mutex held */ 825d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t _snd_pcm_share_mmap_commit(snd_pcm_t *pcm, 826d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, 827d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 828d5ac70f0Sopenharmony_ci{ 829d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 830d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 831d5ac70f0Sopenharmony_ci snd_pcm_t *spcm = slave->pcm; 832d5ac70f0Sopenharmony_ci snd_pcm_sframes_t ret; 833d5ac70f0Sopenharmony_ci snd_pcm_sframes_t frames; 834d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK && 835d5ac70f0Sopenharmony_ci share->state == SND_PCM_STATE_RUNNING) { 836d5ac70f0Sopenharmony_ci frames = *spcm->appl.ptr - share->appl_ptr; 837d5ac70f0Sopenharmony_ci if (frames > (snd_pcm_sframes_t)pcm->buffer_size) 838d5ac70f0Sopenharmony_ci frames -= pcm->boundary; 839d5ac70f0Sopenharmony_ci else if (frames < -(snd_pcm_sframes_t)pcm->buffer_size) 840d5ac70f0Sopenharmony_ci frames += pcm->boundary; 841d5ac70f0Sopenharmony_ci if (frames > 0) { 842d5ac70f0Sopenharmony_ci /* Latecomer PCM */ 843d5ac70f0Sopenharmony_ci ret = snd_pcm_rewind(spcm, frames); 844d5ac70f0Sopenharmony_ci if (ret < 0) 845d5ac70f0Sopenharmony_ci return ret; 846d5ac70f0Sopenharmony_ci } 847d5ac70f0Sopenharmony_ci } 848d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, size); 849d5ac70f0Sopenharmony_ci if (share->state == SND_PCM_STATE_RUNNING) { 850d5ac70f0Sopenharmony_ci frames = _snd_pcm_share_slave_forward(slave); 851d5ac70f0Sopenharmony_ci if (frames > 0) { 852d5ac70f0Sopenharmony_ci snd_pcm_sframes_t err; 853d5ac70f0Sopenharmony_ci err = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), frames); 854d5ac70f0Sopenharmony_ci if (err < 0) { 855d5ac70f0Sopenharmony_ci SYSMSG("snd_pcm_mmap_commit error"); 856d5ac70f0Sopenharmony_ci return err; 857d5ac70f0Sopenharmony_ci } 858d5ac70f0Sopenharmony_ci if (err != frames) { 859d5ac70f0Sopenharmony_ci SYSMSG("commit returns %ld for size %ld", err, frames); 860d5ac70f0Sopenharmony_ci return err; 861d5ac70f0Sopenharmony_ci } 862d5ac70f0Sopenharmony_ci } 863d5ac70f0Sopenharmony_ci _snd_pcm_share_update(pcm); 864d5ac70f0Sopenharmony_ci } 865d5ac70f0Sopenharmony_ci return size; 866d5ac70f0Sopenharmony_ci} 867d5ac70f0Sopenharmony_ci 868d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_share_mmap_commit(snd_pcm_t *pcm, 869d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 870d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size) 871d5ac70f0Sopenharmony_ci{ 872d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 873d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 874d5ac70f0Sopenharmony_ci snd_pcm_sframes_t ret; 875d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 876d5ac70f0Sopenharmony_ci ret = _snd_pcm_share_mmap_commit(pcm, offset, size); 877d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 878d5ac70f0Sopenharmony_ci return ret; 879d5ac70f0Sopenharmony_ci} 880d5ac70f0Sopenharmony_ci 881d5ac70f0Sopenharmony_cistatic int snd_pcm_share_prepare(snd_pcm_t *pcm) 882d5ac70f0Sopenharmony_ci{ 883d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 884d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 885d5ac70f0Sopenharmony_ci int err = 0; 886d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 887d5ac70f0Sopenharmony_ci switch (share->state) { 888d5ac70f0Sopenharmony_ci case SND_PCM_STATE_OPEN: 889d5ac70f0Sopenharmony_ci err = -EBADFD; 890d5ac70f0Sopenharmony_ci goto _end; 891d5ac70f0Sopenharmony_ci case SND_PCM_STATE_RUNNING: 892d5ac70f0Sopenharmony_ci err = -EBUSY; 893d5ac70f0Sopenharmony_ci goto _end; 894d5ac70f0Sopenharmony_ci case SND_PCM_STATE_PREPARED: 895d5ac70f0Sopenharmony_ci err = 0; 896d5ac70f0Sopenharmony_ci goto _end; 897d5ac70f0Sopenharmony_ci default: /* nothing todo */ 898d5ac70f0Sopenharmony_ci break; 899d5ac70f0Sopenharmony_ci } 900d5ac70f0Sopenharmony_ci if (slave->prepared_count == 0) { 901d5ac70f0Sopenharmony_ci err = snd_pcm_prepare(slave->pcm); 902d5ac70f0Sopenharmony_ci if (err < 0) 903d5ac70f0Sopenharmony_ci goto _end; 904d5ac70f0Sopenharmony_ci } 905d5ac70f0Sopenharmony_ci slave->prepared_count++; 906d5ac70f0Sopenharmony_ci share->hw_ptr = 0; 907d5ac70f0Sopenharmony_ci share->appl_ptr = 0; 908d5ac70f0Sopenharmony_ci share->state = SND_PCM_STATE_PREPARED; 909d5ac70f0Sopenharmony_ci _end: 910d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 911d5ac70f0Sopenharmony_ci return err; 912d5ac70f0Sopenharmony_ci} 913d5ac70f0Sopenharmony_ci 914d5ac70f0Sopenharmony_cistatic int snd_pcm_share_reset(snd_pcm_t *pcm) 915d5ac70f0Sopenharmony_ci{ 916d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 917d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 918d5ac70f0Sopenharmony_ci int err = 0; 919d5ac70f0Sopenharmony_ci /* FIXME? */ 920d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 921d5ac70f0Sopenharmony_ci snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels, pcm->buffer_size, pcm->format); 922d5ac70f0Sopenharmony_ci share->hw_ptr = *slave->pcm->hw.ptr; 923d5ac70f0Sopenharmony_ci share->appl_ptr = share->hw_ptr; 924d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 925d5ac70f0Sopenharmony_ci return err; 926d5ac70f0Sopenharmony_ci} 927d5ac70f0Sopenharmony_ci 928d5ac70f0Sopenharmony_cistatic int snd_pcm_share_start(snd_pcm_t *pcm) 929d5ac70f0Sopenharmony_ci{ 930d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 931d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 932d5ac70f0Sopenharmony_ci snd_pcm_t *spcm = slave->pcm; 933d5ac70f0Sopenharmony_ci int err = 0; 934d5ac70f0Sopenharmony_ci if (share->state != SND_PCM_STATE_PREPARED) 935d5ac70f0Sopenharmony_ci return -EBADFD; 936d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 937d5ac70f0Sopenharmony_ci share->state = SND_PCM_STATE_RUNNING; 938d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 939d5ac70f0Sopenharmony_ci snd_pcm_uframes_t hw_avail = snd_pcm_mmap_playback_hw_avail(pcm); 940d5ac70f0Sopenharmony_ci snd_pcm_uframes_t xfer = 0; 941d5ac70f0Sopenharmony_ci if (hw_avail == 0) { 942d5ac70f0Sopenharmony_ci err = -EPIPE; 943d5ac70f0Sopenharmony_ci goto _end; 944d5ac70f0Sopenharmony_ci } 945d5ac70f0Sopenharmony_ci if (slave->running_count) { 946d5ac70f0Sopenharmony_ci snd_pcm_sframes_t sd; 947d5ac70f0Sopenharmony_ci err = snd_pcm_delay(spcm, &sd); 948d5ac70f0Sopenharmony_ci if (err < 0) 949d5ac70f0Sopenharmony_ci goto _end; 950d5ac70f0Sopenharmony_ci err = snd_pcm_rewind(spcm, sd); 951d5ac70f0Sopenharmony_ci if (err < 0) 952d5ac70f0Sopenharmony_ci goto _end; 953d5ac70f0Sopenharmony_ci } 954d5ac70f0Sopenharmony_ci assert(share->hw_ptr == 0); 955d5ac70f0Sopenharmony_ci share->hw_ptr = *spcm->hw.ptr; 956d5ac70f0Sopenharmony_ci share->appl_ptr = *spcm->appl.ptr; 957d5ac70f0Sopenharmony_ci while (xfer < hw_avail) { 958d5ac70f0Sopenharmony_ci snd_pcm_uframes_t frames = hw_avail - xfer; 959d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset = snd_pcm_mmap_offset(pcm); 960d5ac70f0Sopenharmony_ci snd_pcm_uframes_t cont = pcm->buffer_size - offset; 961d5ac70f0Sopenharmony_ci if (cont < frames) 962d5ac70f0Sopenharmony_ci frames = cont; 963d5ac70f0Sopenharmony_ci if (pcm->stopped_areas != NULL) 964d5ac70f0Sopenharmony_ci snd_pcm_areas_copy(pcm->running_areas, offset, 965d5ac70f0Sopenharmony_ci pcm->stopped_areas, xfer, 966d5ac70f0Sopenharmony_ci pcm->channels, frames, 967d5ac70f0Sopenharmony_ci pcm->format); 968d5ac70f0Sopenharmony_ci xfer += frames; 969d5ac70f0Sopenharmony_ci } 970d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, hw_avail); 971d5ac70f0Sopenharmony_ci if (slave->running_count == 0) { 972d5ac70f0Sopenharmony_ci snd_pcm_sframes_t res; 973d5ac70f0Sopenharmony_ci res = snd_pcm_mmap_commit(spcm, snd_pcm_mmap_offset(spcm), hw_avail); 974d5ac70f0Sopenharmony_ci if (res < 0) { 975d5ac70f0Sopenharmony_ci err = res; 976d5ac70f0Sopenharmony_ci goto _end; 977d5ac70f0Sopenharmony_ci } 978d5ac70f0Sopenharmony_ci assert((snd_pcm_uframes_t)res == hw_avail); 979d5ac70f0Sopenharmony_ci } 980d5ac70f0Sopenharmony_ci } 981d5ac70f0Sopenharmony_ci if (slave->running_count == 0) { 982d5ac70f0Sopenharmony_ci err = snd_pcm_start(spcm); 983d5ac70f0Sopenharmony_ci if (err < 0) 984d5ac70f0Sopenharmony_ci goto _end; 985d5ac70f0Sopenharmony_ci } 986d5ac70f0Sopenharmony_ci slave->running_count++; 987d5ac70f0Sopenharmony_ci _snd_pcm_share_update(pcm); 988d5ac70f0Sopenharmony_ci gettimestamp(&share->trigger_tstamp, pcm->tstamp_type); 989d5ac70f0Sopenharmony_ci _end: 990d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 991d5ac70f0Sopenharmony_ci return err; 992d5ac70f0Sopenharmony_ci} 993d5ac70f0Sopenharmony_ci 994d5ac70f0Sopenharmony_cistatic int snd_pcm_share_pause(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int enable ATTRIBUTE_UNUSED) 995d5ac70f0Sopenharmony_ci{ 996d5ac70f0Sopenharmony_ci return -ENOSYS; 997d5ac70f0Sopenharmony_ci} 998d5ac70f0Sopenharmony_ci 999d5ac70f0Sopenharmony_cistatic int snd_pcm_share_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 1000d5ac70f0Sopenharmony_ci{ 1001d5ac70f0Sopenharmony_ci return -ENXIO; 1002d5ac70f0Sopenharmony_ci} 1003d5ac70f0Sopenharmony_ci 1004d5ac70f0Sopenharmony_cistatic int snd_pcm_share_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) 1005d5ac70f0Sopenharmony_ci{ 1006d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1007d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1008d5ac70f0Sopenharmony_ci unsigned int channel = info->channel; 1009d5ac70f0Sopenharmony_ci int c = share->slave_channels[channel]; 1010d5ac70f0Sopenharmony_ci int err; 1011d5ac70f0Sopenharmony_ci info->channel = c; 1012d5ac70f0Sopenharmony_ci err = snd_pcm_channel_info(slave->pcm, info); 1013d5ac70f0Sopenharmony_ci info->channel = channel; 1014d5ac70f0Sopenharmony_ci return err; 1015d5ac70f0Sopenharmony_ci} 1016d5ac70f0Sopenharmony_ci 1017d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t _snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 1018d5ac70f0Sopenharmony_ci{ 1019d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1020d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1021d5ac70f0Sopenharmony_ci snd_pcm_sframes_t n; 1022d5ac70f0Sopenharmony_ci switch (share->state) { 1023d5ac70f0Sopenharmony_ci case SND_PCM_STATE_RUNNING: 1024d5ac70f0Sopenharmony_ci break; 1025d5ac70f0Sopenharmony_ci case SND_PCM_STATE_PREPARED: 1026d5ac70f0Sopenharmony_ci if (pcm->stream != SND_PCM_STREAM_PLAYBACK) 1027d5ac70f0Sopenharmony_ci return -EBADFD; 1028d5ac70f0Sopenharmony_ci break; 1029d5ac70f0Sopenharmony_ci case SND_PCM_STATE_DRAINING: 1030d5ac70f0Sopenharmony_ci if (pcm->stream != SND_PCM_STREAM_CAPTURE) 1031d5ac70f0Sopenharmony_ci return -EBADFD; 1032d5ac70f0Sopenharmony_ci break; 1033d5ac70f0Sopenharmony_ci case SND_PCM_STATE_XRUN: 1034d5ac70f0Sopenharmony_ci return -EPIPE; 1035d5ac70f0Sopenharmony_ci default: 1036d5ac70f0Sopenharmony_ci return -EBADFD; 1037d5ac70f0Sopenharmony_ci } 1038d5ac70f0Sopenharmony_ci n = snd_pcm_mmap_hw_avail(pcm); 1039d5ac70f0Sopenharmony_ci assert(n >= 0); 1040d5ac70f0Sopenharmony_ci if ((snd_pcm_uframes_t)n > frames) 1041d5ac70f0Sopenharmony_ci frames = n; 1042d5ac70f0Sopenharmony_ci if (share->state == SND_PCM_STATE_RUNNING && frames > 0) { 1043d5ac70f0Sopenharmony_ci snd_pcm_sframes_t ret = snd_pcm_rewind(slave->pcm, frames); 1044d5ac70f0Sopenharmony_ci if (ret < 0) 1045d5ac70f0Sopenharmony_ci return ret; 1046d5ac70f0Sopenharmony_ci frames = ret; 1047d5ac70f0Sopenharmony_ci } 1048d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_backward(pcm, frames); 1049d5ac70f0Sopenharmony_ci _snd_pcm_share_update(pcm); 1050d5ac70f0Sopenharmony_ci return n; 1051d5ac70f0Sopenharmony_ci} 1052d5ac70f0Sopenharmony_ci 1053d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_share_rewindable(snd_pcm_t *pcm) 1054d5ac70f0Sopenharmony_ci{ 1055d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1056d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1057d5ac70f0Sopenharmony_ci snd_pcm_sframes_t ret; 1058d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 1059d5ac70f0Sopenharmony_ci ret = snd_pcm_rewindable(slave->pcm); 1060d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 1061d5ac70f0Sopenharmony_ci return ret; 1062d5ac70f0Sopenharmony_ci} 1063d5ac70f0Sopenharmony_ci 1064d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_share_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 1065d5ac70f0Sopenharmony_ci{ 1066d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1067d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1068d5ac70f0Sopenharmony_ci snd_pcm_sframes_t ret; 1069d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 1070d5ac70f0Sopenharmony_ci ret = _snd_pcm_share_rewind(pcm, frames); 1071d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 1072d5ac70f0Sopenharmony_ci return ret; 1073d5ac70f0Sopenharmony_ci} 1074d5ac70f0Sopenharmony_ci 1075d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t _snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 1076d5ac70f0Sopenharmony_ci{ 1077d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1078d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1079d5ac70f0Sopenharmony_ci snd_pcm_sframes_t n; 1080d5ac70f0Sopenharmony_ci switch (share->state) { 1081d5ac70f0Sopenharmony_ci case SND_PCM_STATE_RUNNING: 1082d5ac70f0Sopenharmony_ci break; 1083d5ac70f0Sopenharmony_ci case SND_PCM_STATE_PREPARED: 1084d5ac70f0Sopenharmony_ci if (pcm->stream != SND_PCM_STREAM_PLAYBACK) 1085d5ac70f0Sopenharmony_ci return -EBADFD; 1086d5ac70f0Sopenharmony_ci break; 1087d5ac70f0Sopenharmony_ci case SND_PCM_STATE_DRAINING: 1088d5ac70f0Sopenharmony_ci if (pcm->stream != SND_PCM_STREAM_CAPTURE) 1089d5ac70f0Sopenharmony_ci return -EBADFD; 1090d5ac70f0Sopenharmony_ci break; 1091d5ac70f0Sopenharmony_ci case SND_PCM_STATE_XRUN: 1092d5ac70f0Sopenharmony_ci return -EPIPE; 1093d5ac70f0Sopenharmony_ci default: 1094d5ac70f0Sopenharmony_ci return -EBADFD; 1095d5ac70f0Sopenharmony_ci } 1096d5ac70f0Sopenharmony_ci n = snd_pcm_mmap_avail(pcm); 1097d5ac70f0Sopenharmony_ci if ((snd_pcm_uframes_t)n > frames) 1098d5ac70f0Sopenharmony_ci frames = n; 1099d5ac70f0Sopenharmony_ci if (share->state == SND_PCM_STATE_RUNNING && frames > 0) { 1100d5ac70f0Sopenharmony_ci snd_pcm_sframes_t ret = INTERNAL(snd_pcm_forward)(slave->pcm, frames); 1101d5ac70f0Sopenharmony_ci if (ret < 0) 1102d5ac70f0Sopenharmony_ci return ret; 1103d5ac70f0Sopenharmony_ci frames = ret; 1104d5ac70f0Sopenharmony_ci } 1105d5ac70f0Sopenharmony_ci snd_pcm_mmap_appl_forward(pcm, frames); 1106d5ac70f0Sopenharmony_ci _snd_pcm_share_update(pcm); 1107d5ac70f0Sopenharmony_ci return n; 1108d5ac70f0Sopenharmony_ci} 1109d5ac70f0Sopenharmony_ci 1110d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_share_forwardable(snd_pcm_t *pcm) 1111d5ac70f0Sopenharmony_ci{ 1112d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1113d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1114d5ac70f0Sopenharmony_ci snd_pcm_sframes_t ret; 1115d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 1116d5ac70f0Sopenharmony_ci ret = snd_pcm_forwardable(slave->pcm); 1117d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 1118d5ac70f0Sopenharmony_ci return ret; 1119d5ac70f0Sopenharmony_ci} 1120d5ac70f0Sopenharmony_ci 1121d5ac70f0Sopenharmony_cistatic snd_pcm_sframes_t snd_pcm_share_forward(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 1122d5ac70f0Sopenharmony_ci{ 1123d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1124d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1125d5ac70f0Sopenharmony_ci snd_pcm_sframes_t ret; 1126d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 1127d5ac70f0Sopenharmony_ci ret = _snd_pcm_share_forward(pcm, frames); 1128d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 1129d5ac70f0Sopenharmony_ci return ret; 1130d5ac70f0Sopenharmony_ci} 1131d5ac70f0Sopenharmony_ci 1132d5ac70f0Sopenharmony_ci/* Warning: take the mutex before to call this */ 1133d5ac70f0Sopenharmony_cistatic void _snd_pcm_share_stop(snd_pcm_t *pcm, snd_pcm_state_t state) 1134d5ac70f0Sopenharmony_ci{ 1135d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1136d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1137d5ac70f0Sopenharmony_ci#if 0 1138d5ac70f0Sopenharmony_ci if (!pcm->mmap_channels) { 1139d5ac70f0Sopenharmony_ci /* PCM closing already begun in the main thread */ 1140d5ac70f0Sopenharmony_ci return; 1141d5ac70f0Sopenharmony_ci } 1142d5ac70f0Sopenharmony_ci#endif 1143d5ac70f0Sopenharmony_ci gettimestamp(&share->trigger_tstamp, pcm->tstamp_type); 1144d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_CAPTURE) { 1145d5ac70f0Sopenharmony_ci snd_pcm_areas_copy(pcm->stopped_areas, 0, 1146d5ac70f0Sopenharmony_ci pcm->running_areas, 0, 1147d5ac70f0Sopenharmony_ci pcm->channels, pcm->buffer_size, 1148d5ac70f0Sopenharmony_ci pcm->format); 1149d5ac70f0Sopenharmony_ci } else if (slave->running_count > 1) { 1150d5ac70f0Sopenharmony_ci int err; 1151d5ac70f0Sopenharmony_ci snd_pcm_sframes_t delay; 1152d5ac70f0Sopenharmony_ci snd_pcm_areas_silence(pcm->running_areas, 0, pcm->channels, 1153d5ac70f0Sopenharmony_ci pcm->buffer_size, pcm->format); 1154d5ac70f0Sopenharmony_ci err = snd_pcm_delay(slave->pcm, &delay); 1155d5ac70f0Sopenharmony_ci if (err >= 0 && delay > 0) 1156d5ac70f0Sopenharmony_ci snd_pcm_rewind(slave->pcm, delay); 1157d5ac70f0Sopenharmony_ci share->drain_silenced = 0; 1158d5ac70f0Sopenharmony_ci } 1159d5ac70f0Sopenharmony_ci share->state = state; 1160d5ac70f0Sopenharmony_ci slave->prepared_count--; 1161d5ac70f0Sopenharmony_ci slave->running_count--; 1162d5ac70f0Sopenharmony_ci if (slave->running_count == 0) { 1163d5ac70f0Sopenharmony_ci int err = snd_pcm_drop(slave->pcm); 1164d5ac70f0Sopenharmony_ci assert(err >= 0); 1165d5ac70f0Sopenharmony_ci } 1166d5ac70f0Sopenharmony_ci} 1167d5ac70f0Sopenharmony_ci 1168d5ac70f0Sopenharmony_cistatic int snd_pcm_share_drain(snd_pcm_t *pcm) 1169d5ac70f0Sopenharmony_ci{ 1170d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1171d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1172d5ac70f0Sopenharmony_ci int err = 0; 1173d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 1174d5ac70f0Sopenharmony_ci switch (share->state) { 1175d5ac70f0Sopenharmony_ci case SND_PCM_STATE_OPEN: 1176d5ac70f0Sopenharmony_ci err = -EBADFD; 1177d5ac70f0Sopenharmony_ci goto _end; 1178d5ac70f0Sopenharmony_ci case SND_PCM_STATE_PREPARED: 1179d5ac70f0Sopenharmony_ci share->state = SND_PCM_STATE_SETUP; 1180d5ac70f0Sopenharmony_ci goto _end; 1181d5ac70f0Sopenharmony_ci case SND_PCM_STATE_SETUP: 1182d5ac70f0Sopenharmony_ci goto _end; 1183d5ac70f0Sopenharmony_ci default: 1184d5ac70f0Sopenharmony_ci break; 1185d5ac70f0Sopenharmony_ci } 1186d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { 1187d5ac70f0Sopenharmony_ci switch (share->state) { 1188d5ac70f0Sopenharmony_ci case SND_PCM_STATE_XRUN: 1189d5ac70f0Sopenharmony_ci share->state = SND_PCM_STATE_SETUP; 1190d5ac70f0Sopenharmony_ci goto _end; 1191d5ac70f0Sopenharmony_ci case SND_PCM_STATE_DRAINING: 1192d5ac70f0Sopenharmony_ci case SND_PCM_STATE_RUNNING: 1193d5ac70f0Sopenharmony_ci share->state = SND_PCM_STATE_DRAINING; 1194d5ac70f0Sopenharmony_ci _snd_pcm_share_update(pcm); 1195d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 1196d5ac70f0Sopenharmony_ci if (!(pcm->mode & SND_PCM_NONBLOCK)) 1197d5ac70f0Sopenharmony_ci snd_pcm_wait(pcm, SND_PCM_WAIT_DRAIN); 1198d5ac70f0Sopenharmony_ci return 0; 1199d5ac70f0Sopenharmony_ci default: 1200d5ac70f0Sopenharmony_ci assert(0); 1201d5ac70f0Sopenharmony_ci break; 1202d5ac70f0Sopenharmony_ci } 1203d5ac70f0Sopenharmony_ci } else { 1204d5ac70f0Sopenharmony_ci switch (share->state) { 1205d5ac70f0Sopenharmony_ci case SND_PCM_STATE_RUNNING: 1206d5ac70f0Sopenharmony_ci _snd_pcm_share_stop(pcm, SND_PCM_STATE_DRAINING); 1207d5ac70f0Sopenharmony_ci _snd_pcm_share_update(pcm); 1208d5ac70f0Sopenharmony_ci /* Fall through */ 1209d5ac70f0Sopenharmony_ci case SND_PCM_STATE_XRUN: 1210d5ac70f0Sopenharmony_ci case SND_PCM_STATE_DRAINING: 1211d5ac70f0Sopenharmony_ci if (snd_pcm_mmap_capture_avail(pcm) <= 0) 1212d5ac70f0Sopenharmony_ci share->state = SND_PCM_STATE_SETUP; 1213d5ac70f0Sopenharmony_ci else 1214d5ac70f0Sopenharmony_ci share->state = SND_PCM_STATE_DRAINING; 1215d5ac70f0Sopenharmony_ci break; 1216d5ac70f0Sopenharmony_ci default: 1217d5ac70f0Sopenharmony_ci assert(0); 1218d5ac70f0Sopenharmony_ci break; 1219d5ac70f0Sopenharmony_ci } 1220d5ac70f0Sopenharmony_ci } 1221d5ac70f0Sopenharmony_ci _end: 1222d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 1223d5ac70f0Sopenharmony_ci return err; 1224d5ac70f0Sopenharmony_ci} 1225d5ac70f0Sopenharmony_ci 1226d5ac70f0Sopenharmony_cistatic int snd_pcm_share_drop(snd_pcm_t *pcm) 1227d5ac70f0Sopenharmony_ci{ 1228d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1229d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1230d5ac70f0Sopenharmony_ci int err = 0; 1231d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 1232d5ac70f0Sopenharmony_ci switch (share->state) { 1233d5ac70f0Sopenharmony_ci case SND_PCM_STATE_OPEN: 1234d5ac70f0Sopenharmony_ci err = -EBADFD; 1235d5ac70f0Sopenharmony_ci goto _end; 1236d5ac70f0Sopenharmony_ci case SND_PCM_STATE_SETUP: 1237d5ac70f0Sopenharmony_ci break; 1238d5ac70f0Sopenharmony_ci case SND_PCM_STATE_DRAINING: 1239d5ac70f0Sopenharmony_ci if (pcm->stream == SND_PCM_STREAM_CAPTURE) { 1240d5ac70f0Sopenharmony_ci share->state = SND_PCM_STATE_SETUP; 1241d5ac70f0Sopenharmony_ci break; 1242d5ac70f0Sopenharmony_ci } 1243d5ac70f0Sopenharmony_ci /* Fall through */ 1244d5ac70f0Sopenharmony_ci case SND_PCM_STATE_RUNNING: 1245d5ac70f0Sopenharmony_ci _snd_pcm_share_stop(pcm, SND_PCM_STATE_SETUP); 1246d5ac70f0Sopenharmony_ci _snd_pcm_share_update(pcm); 1247d5ac70f0Sopenharmony_ci break; 1248d5ac70f0Sopenharmony_ci case SND_PCM_STATE_PREPARED: 1249d5ac70f0Sopenharmony_ci case SND_PCM_STATE_XRUN: 1250d5ac70f0Sopenharmony_ci share->state = SND_PCM_STATE_SETUP; 1251d5ac70f0Sopenharmony_ci break; 1252d5ac70f0Sopenharmony_ci default: 1253d5ac70f0Sopenharmony_ci assert(0); 1254d5ac70f0Sopenharmony_ci break; 1255d5ac70f0Sopenharmony_ci } 1256d5ac70f0Sopenharmony_ci 1257d5ac70f0Sopenharmony_ci share->appl_ptr = share->hw_ptr = 0; 1258d5ac70f0Sopenharmony_ci _end: 1259d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 1260d5ac70f0Sopenharmony_ci return err; 1261d5ac70f0Sopenharmony_ci} 1262d5ac70f0Sopenharmony_ci 1263d5ac70f0Sopenharmony_cistatic int snd_pcm_share_close(snd_pcm_t *pcm) 1264d5ac70f0Sopenharmony_ci{ 1265d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1266d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1267d5ac70f0Sopenharmony_ci int err = 0; 1268d5ac70f0Sopenharmony_ci 1269d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&snd_pcm_share_slaves_mutex); 1270d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 1271d5ac70f0Sopenharmony_ci slave->open_count--; 1272d5ac70f0Sopenharmony_ci if (slave->open_count == 0) { 1273d5ac70f0Sopenharmony_ci pthread_cond_signal(&slave->poll_cond); 1274d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 1275d5ac70f0Sopenharmony_ci err = pthread_join(slave->thread, 0); 1276d5ac70f0Sopenharmony_ci assert(err == 0); 1277d5ac70f0Sopenharmony_ci err = snd_pcm_close(slave->pcm); 1278d5ac70f0Sopenharmony_ci pthread_mutex_destroy(&slave->mutex); 1279d5ac70f0Sopenharmony_ci pthread_cond_destroy(&slave->poll_cond); 1280d5ac70f0Sopenharmony_ci list_del(&slave->list); 1281d5ac70f0Sopenharmony_ci free(slave); 1282d5ac70f0Sopenharmony_ci list_del(&share->list); 1283d5ac70f0Sopenharmony_ci } else { 1284d5ac70f0Sopenharmony_ci list_del(&share->list); 1285d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 1286d5ac70f0Sopenharmony_ci } 1287d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex); 1288d5ac70f0Sopenharmony_ci close(share->client_socket); 1289d5ac70f0Sopenharmony_ci close(share->slave_socket); 1290d5ac70f0Sopenharmony_ci free(share->slave_channels); 1291d5ac70f0Sopenharmony_ci free(share); 1292d5ac70f0Sopenharmony_ci return err; 1293d5ac70f0Sopenharmony_ci} 1294d5ac70f0Sopenharmony_ci 1295d5ac70f0Sopenharmony_cistatic int snd_pcm_share_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 1296d5ac70f0Sopenharmony_ci{ 1297d5ac70f0Sopenharmony_ci return 0; 1298d5ac70f0Sopenharmony_ci} 1299d5ac70f0Sopenharmony_ci 1300d5ac70f0Sopenharmony_cistatic int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) 1301d5ac70f0Sopenharmony_ci{ 1302d5ac70f0Sopenharmony_ci return 0; 1303d5ac70f0Sopenharmony_ci} 1304d5ac70f0Sopenharmony_ci 1305d5ac70f0Sopenharmony_cistatic void snd_pcm_share_dump(snd_pcm_t *pcm, snd_output_t *out) 1306d5ac70f0Sopenharmony_ci{ 1307d5ac70f0Sopenharmony_ci snd_pcm_share_t *share = pcm->private_data; 1308d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = share->slave; 1309d5ac70f0Sopenharmony_ci unsigned int k; 1310d5ac70f0Sopenharmony_ci snd_output_printf(out, "Share PCM\n"); 1311d5ac70f0Sopenharmony_ci snd_output_printf(out, " Channel bindings:\n"); 1312d5ac70f0Sopenharmony_ci for (k = 0; k < share->channels; ++k) 1313d5ac70f0Sopenharmony_ci snd_output_printf(out, " %d: %d\n", k, share->slave_channels[k]); 1314d5ac70f0Sopenharmony_ci if (pcm->setup) { 1315d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 1316d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 1317d5ac70f0Sopenharmony_ci } 1318d5ac70f0Sopenharmony_ci snd_output_printf(out, "Slave: "); 1319d5ac70f0Sopenharmony_ci snd_pcm_dump(slave->pcm, out); 1320d5ac70f0Sopenharmony_ci} 1321d5ac70f0Sopenharmony_ci 1322d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_share_ops = { 1323d5ac70f0Sopenharmony_ci .close = snd_pcm_share_close, 1324d5ac70f0Sopenharmony_ci .info = snd_pcm_share_info, 1325d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_share_hw_refine, 1326d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_share_hw_params, 1327d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_share_hw_free, 1328d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_share_sw_params, 1329d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_share_channel_info, 1330d5ac70f0Sopenharmony_ci .dump = snd_pcm_share_dump, 1331d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_share_nonblock, 1332d5ac70f0Sopenharmony_ci .async = snd_pcm_share_async, 1333d5ac70f0Sopenharmony_ci .mmap = snd_pcm_share_mmap, 1334d5ac70f0Sopenharmony_ci .munmap = snd_pcm_share_munmap, 1335d5ac70f0Sopenharmony_ci}; 1336d5ac70f0Sopenharmony_ci 1337d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_share_fast_ops = { 1338d5ac70f0Sopenharmony_ci .status = snd_pcm_share_status, 1339d5ac70f0Sopenharmony_ci .state = snd_pcm_share_state, 1340d5ac70f0Sopenharmony_ci .hwsync = snd_pcm_share_hwsync, 1341d5ac70f0Sopenharmony_ci .delay = snd_pcm_share_delay, 1342d5ac70f0Sopenharmony_ci .prepare = snd_pcm_share_prepare, 1343d5ac70f0Sopenharmony_ci .reset = snd_pcm_share_reset, 1344d5ac70f0Sopenharmony_ci .start = snd_pcm_share_start, 1345d5ac70f0Sopenharmony_ci .drop = snd_pcm_share_drop, 1346d5ac70f0Sopenharmony_ci .drain = snd_pcm_share_drain, 1347d5ac70f0Sopenharmony_ci .pause = snd_pcm_share_pause, 1348d5ac70f0Sopenharmony_ci .writei = snd_pcm_mmap_writei, 1349d5ac70f0Sopenharmony_ci .writen = snd_pcm_mmap_writen, 1350d5ac70f0Sopenharmony_ci .readi = snd_pcm_mmap_readi, 1351d5ac70f0Sopenharmony_ci .readn = snd_pcm_mmap_readn, 1352d5ac70f0Sopenharmony_ci .rewindable = snd_pcm_share_rewindable, 1353d5ac70f0Sopenharmony_ci .rewind = snd_pcm_share_rewind, 1354d5ac70f0Sopenharmony_ci .forwardable = snd_pcm_share_forwardable, 1355d5ac70f0Sopenharmony_ci .forward = snd_pcm_share_forward, 1356d5ac70f0Sopenharmony_ci .resume = snd_pcm_share_resume, 1357d5ac70f0Sopenharmony_ci .avail_update = snd_pcm_share_avail_update, 1358d5ac70f0Sopenharmony_ci .htimestamp = snd_pcm_share_htimestamp, 1359d5ac70f0Sopenharmony_ci .mmap_commit = snd_pcm_share_mmap_commit, 1360d5ac70f0Sopenharmony_ci}; 1361d5ac70f0Sopenharmony_ci 1362d5ac70f0Sopenharmony_ci/** 1363d5ac70f0Sopenharmony_ci * \brief Creates a new Share PCM 1364d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 1365d5ac70f0Sopenharmony_ci * \param name Name of PCM 1366d5ac70f0Sopenharmony_ci * \param sname Slave name 1367d5ac70f0Sopenharmony_ci * \param sformat Slave format 1368d5ac70f0Sopenharmony_ci * \param srate Slave rate 1369d5ac70f0Sopenharmony_ci * \param schannels Slave channels 1370d5ac70f0Sopenharmony_ci * \param speriod_time Slave period time 1371d5ac70f0Sopenharmony_ci * \param sbuffer_time Slave buffer time 1372d5ac70f0Sopenharmony_ci * \param channels Count of channels 1373d5ac70f0Sopenharmony_ci * \param channels_map Map of channels 1374d5ac70f0Sopenharmony_ci * \param stream Direction 1375d5ac70f0Sopenharmony_ci * \param mode PCM mode 1376d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 1377d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 1378d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 1379d5ac70f0Sopenharmony_ci * changed in future. 1380d5ac70f0Sopenharmony_ci */ 1381d5ac70f0Sopenharmony_ciint snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname, 1382d5ac70f0Sopenharmony_ci snd_pcm_format_t sformat, int srate, 1383d5ac70f0Sopenharmony_ci unsigned int schannels, 1384d5ac70f0Sopenharmony_ci int speriod_time, int sbuffer_time, 1385d5ac70f0Sopenharmony_ci unsigned int channels, unsigned int *channels_map, 1386d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 1387d5ac70f0Sopenharmony_ci{ 1388d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 1389d5ac70f0Sopenharmony_ci snd_pcm_share_t *share; 1390d5ac70f0Sopenharmony_ci int err; 1391d5ac70f0Sopenharmony_ci struct list_head *i; 1392d5ac70f0Sopenharmony_ci char slave_map[32] = { 0 }; 1393d5ac70f0Sopenharmony_ci unsigned int k; 1394d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *slave = NULL; 1395d5ac70f0Sopenharmony_ci int sd[2]; 1396d5ac70f0Sopenharmony_ci 1397d5ac70f0Sopenharmony_ci assert(pcmp); 1398d5ac70f0Sopenharmony_ci assert(channels > 0 && sname && channels_map); 1399d5ac70f0Sopenharmony_ci 1400d5ac70f0Sopenharmony_ci for (k = 0; k < channels; ++k) { 1401d5ac70f0Sopenharmony_ci if (channels_map[k] >= sizeof(slave_map) / sizeof(slave_map[0])) { 1402d5ac70f0Sopenharmony_ci SNDERR("Invalid slave channel (%d) in binding", channels_map[k]); 1403d5ac70f0Sopenharmony_ci return -EINVAL; 1404d5ac70f0Sopenharmony_ci } 1405d5ac70f0Sopenharmony_ci if (slave_map[channels_map[k]]) { 1406d5ac70f0Sopenharmony_ci SNDERR("Repeated slave channel (%d) in binding", channels_map[k]); 1407d5ac70f0Sopenharmony_ci return -EINVAL; 1408d5ac70f0Sopenharmony_ci } 1409d5ac70f0Sopenharmony_ci slave_map[channels_map[k]] = 1; 1410d5ac70f0Sopenharmony_ci assert((unsigned)channels_map[k] < schannels); 1411d5ac70f0Sopenharmony_ci } 1412d5ac70f0Sopenharmony_ci 1413d5ac70f0Sopenharmony_ci share = calloc(1, sizeof(snd_pcm_share_t)); 1414d5ac70f0Sopenharmony_ci if (!share) 1415d5ac70f0Sopenharmony_ci return -ENOMEM; 1416d5ac70f0Sopenharmony_ci 1417d5ac70f0Sopenharmony_ci share->channels = channels; 1418d5ac70f0Sopenharmony_ci share->slave_channels = calloc(channels, sizeof(*share->slave_channels)); 1419d5ac70f0Sopenharmony_ci if (!share->slave_channels) { 1420d5ac70f0Sopenharmony_ci free(share); 1421d5ac70f0Sopenharmony_ci return -ENOMEM; 1422d5ac70f0Sopenharmony_ci } 1423d5ac70f0Sopenharmony_ci memcpy(share->slave_channels, channels_map, channels * sizeof(*share->slave_channels)); 1424d5ac70f0Sopenharmony_ci 1425d5ac70f0Sopenharmony_ci err = snd_pcm_new(&pcm, SND_PCM_TYPE_SHARE, name, stream, mode); 1426d5ac70f0Sopenharmony_ci if (err < 0) { 1427d5ac70f0Sopenharmony_ci free(share->slave_channels); 1428d5ac70f0Sopenharmony_ci free(share); 1429d5ac70f0Sopenharmony_ci return err; 1430d5ac70f0Sopenharmony_ci } 1431d5ac70f0Sopenharmony_ci err = socketpair(AF_LOCAL, SOCK_STREAM, 0, sd); 1432d5ac70f0Sopenharmony_ci if (err < 0) { 1433d5ac70f0Sopenharmony_ci snd_pcm_free(pcm); 1434d5ac70f0Sopenharmony_ci free(share->slave_channels); 1435d5ac70f0Sopenharmony_ci free(share); 1436d5ac70f0Sopenharmony_ci return -errno; 1437d5ac70f0Sopenharmony_ci } 1438d5ac70f0Sopenharmony_ci 1439d5ac70f0Sopenharmony_ci if (stream == SND_PCM_STREAM_PLAYBACK) { 1440d5ac70f0Sopenharmony_ci int bufsize = 1; 1441d5ac70f0Sopenharmony_ci err = setsockopt(sd[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)); 1442d5ac70f0Sopenharmony_ci if (err >= 0) { 1443d5ac70f0Sopenharmony_ci struct pollfd pfd; 1444d5ac70f0Sopenharmony_ci pfd.fd = sd[0]; 1445d5ac70f0Sopenharmony_ci pfd.events = POLLOUT; 1446d5ac70f0Sopenharmony_ci while ((err = poll(&pfd, 1, 0)) == 1) { 1447d5ac70f0Sopenharmony_ci char buf[1]; 1448d5ac70f0Sopenharmony_ci err = write(sd[0], buf, 1); 1449d5ac70f0Sopenharmony_ci assert(err != 0); 1450d5ac70f0Sopenharmony_ci if (err != 1) 1451d5ac70f0Sopenharmony_ci break; 1452d5ac70f0Sopenharmony_ci } 1453d5ac70f0Sopenharmony_ci } 1454d5ac70f0Sopenharmony_ci } 1455d5ac70f0Sopenharmony_ci if (err < 0) { 1456d5ac70f0Sopenharmony_ci err = -errno; 1457d5ac70f0Sopenharmony_ci close(sd[0]); 1458d5ac70f0Sopenharmony_ci close(sd[1]); 1459d5ac70f0Sopenharmony_ci snd_pcm_free(pcm); 1460d5ac70f0Sopenharmony_ci free(share->slave_channels); 1461d5ac70f0Sopenharmony_ci free(share); 1462d5ac70f0Sopenharmony_ci return err; 1463d5ac70f0Sopenharmony_ci } 1464d5ac70f0Sopenharmony_ci 1465d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&snd_pcm_share_slaves_mutex); 1466d5ac70f0Sopenharmony_ci list_for_each(i, &snd_pcm_share_slaves) { 1467d5ac70f0Sopenharmony_ci snd_pcm_share_slave_t *s = list_entry(i, snd_pcm_share_slave_t, list); 1468d5ac70f0Sopenharmony_ci if (s->pcm->name && strcmp(s->pcm->name, sname) == 0) { 1469d5ac70f0Sopenharmony_ci slave = s; 1470d5ac70f0Sopenharmony_ci break; 1471d5ac70f0Sopenharmony_ci } 1472d5ac70f0Sopenharmony_ci } 1473d5ac70f0Sopenharmony_ci if (!slave) { 1474d5ac70f0Sopenharmony_ci snd_pcm_t *spcm; 1475d5ac70f0Sopenharmony_ci err = snd_pcm_open(&spcm, sname, stream, mode); 1476d5ac70f0Sopenharmony_ci if (err < 0) { 1477d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex); 1478d5ac70f0Sopenharmony_ci close(sd[0]); 1479d5ac70f0Sopenharmony_ci close(sd[1]); 1480d5ac70f0Sopenharmony_ci snd_pcm_free(pcm); 1481d5ac70f0Sopenharmony_ci free(share->slave_channels); 1482d5ac70f0Sopenharmony_ci free(share); 1483d5ac70f0Sopenharmony_ci return err; 1484d5ac70f0Sopenharmony_ci } 1485d5ac70f0Sopenharmony_ci /* FIXME: bellow is a real ugly hack to get things working */ 1486d5ac70f0Sopenharmony_ci /* there is a memory leak somewhere, but I'm unable to trace it --jk */ 1487d5ac70f0Sopenharmony_ci slave = calloc(1, sizeof(snd_pcm_share_slave_t) * 8); 1488d5ac70f0Sopenharmony_ci if (!slave) { 1489d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex); 1490d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 1491d5ac70f0Sopenharmony_ci close(sd[0]); 1492d5ac70f0Sopenharmony_ci close(sd[1]); 1493d5ac70f0Sopenharmony_ci snd_pcm_free(pcm); 1494d5ac70f0Sopenharmony_ci free(share->slave_channels); 1495d5ac70f0Sopenharmony_ci free(share); 1496d5ac70f0Sopenharmony_ci return err; 1497d5ac70f0Sopenharmony_ci } 1498d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&slave->clients); 1499d5ac70f0Sopenharmony_ci slave->pcm = spcm; 1500d5ac70f0Sopenharmony_ci slave->channels = schannels; 1501d5ac70f0Sopenharmony_ci slave->format = sformat; 1502d5ac70f0Sopenharmony_ci slave->rate = srate; 1503d5ac70f0Sopenharmony_ci slave->period_time = speriod_time; 1504d5ac70f0Sopenharmony_ci slave->buffer_time = sbuffer_time; 1505d5ac70f0Sopenharmony_ci pthread_mutex_init(&slave->mutex, NULL); 1506d5ac70f0Sopenharmony_ci pthread_cond_init(&slave->poll_cond, NULL); 1507d5ac70f0Sopenharmony_ci list_add_tail(&slave->list, &snd_pcm_share_slaves); 1508d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 1509d5ac70f0Sopenharmony_ci err = pthread_create(&slave->thread, NULL, snd_pcm_share_thread, slave); 1510d5ac70f0Sopenharmony_ci assert(err == 0); 1511d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex); 1512d5ac70f0Sopenharmony_ci } else { 1513d5ac70f0Sopenharmony_ci Pthread_mutex_lock(&slave->mutex); 1514d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&snd_pcm_share_slaves_mutex); 1515d5ac70f0Sopenharmony_ci list_for_each(i, &slave->clients) { 1516d5ac70f0Sopenharmony_ci snd_pcm_share_t *sh = list_entry(i, snd_pcm_share_t, list); 1517d5ac70f0Sopenharmony_ci for (k = 0; k < sh->channels; ++k) { 1518d5ac70f0Sopenharmony_ci if (slave_map[sh->slave_channels[k]]) { 1519d5ac70f0Sopenharmony_ci SNDERR("Slave channel %d is already in use", sh->slave_channels[k]); 1520d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 1521d5ac70f0Sopenharmony_ci close(sd[0]); 1522d5ac70f0Sopenharmony_ci close(sd[1]); 1523d5ac70f0Sopenharmony_ci snd_pcm_free(pcm); 1524d5ac70f0Sopenharmony_ci free(share->slave_channels); 1525d5ac70f0Sopenharmony_ci free(share); 1526d5ac70f0Sopenharmony_ci return -EBUSY; 1527d5ac70f0Sopenharmony_ci } 1528d5ac70f0Sopenharmony_ci } 1529d5ac70f0Sopenharmony_ci } 1530d5ac70f0Sopenharmony_ci } 1531d5ac70f0Sopenharmony_ci 1532d5ac70f0Sopenharmony_ci share->slave = slave; 1533d5ac70f0Sopenharmony_ci share->pcm = pcm; 1534d5ac70f0Sopenharmony_ci share->client_socket = sd[0]; 1535d5ac70f0Sopenharmony_ci share->slave_socket = sd[1]; 1536d5ac70f0Sopenharmony_ci 1537d5ac70f0Sopenharmony_ci pcm->mmap_rw = 1; 1538d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_share_ops; 1539d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_share_fast_ops; 1540d5ac70f0Sopenharmony_ci pcm->private_data = share; 1541d5ac70f0Sopenharmony_ci pcm->poll_fd = share->client_socket; 1542d5ac70f0Sopenharmony_ci pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; 1543d5ac70f0Sopenharmony_ci pcm->tstamp_type = slave->pcm->tstamp_type; 1544d5ac70f0Sopenharmony_ci snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0); 1545d5ac70f0Sopenharmony_ci snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0); 1546d5ac70f0Sopenharmony_ci 1547d5ac70f0Sopenharmony_ci slave->open_count++; 1548d5ac70f0Sopenharmony_ci list_add_tail(&share->list, &slave->clients); 1549d5ac70f0Sopenharmony_ci 1550d5ac70f0Sopenharmony_ci Pthread_mutex_unlock(&slave->mutex); 1551d5ac70f0Sopenharmony_ci 1552d5ac70f0Sopenharmony_ci *pcmp = pcm; 1553d5ac70f0Sopenharmony_ci return 0; 1554d5ac70f0Sopenharmony_ci} 1555d5ac70f0Sopenharmony_ci 1556d5ac70f0Sopenharmony_ci/*! \page pcm_plugins 1557d5ac70f0Sopenharmony_ci 1558d5ac70f0Sopenharmony_ci\section pcm_plugins_share Plugin: Share 1559d5ac70f0Sopenharmony_ci 1560d5ac70f0Sopenharmony_ciThis plugin allows sharing of multiple channels with more clients. The access 1561d5ac70f0Sopenharmony_cito each channel is exlusive (samples are not mixed together). It means, if 1562d5ac70f0Sopenharmony_cithe channel zero is used with first client, the channel cannot be used with 1563d5ac70f0Sopenharmony_cisecond one. If you are looking for a mixing plugin, use the 1564d5ac70f0Sopenharmony_ci\ref pcm_plugins_dmix "dmix plugin". 1565d5ac70f0Sopenharmony_ci 1566d5ac70f0Sopenharmony_ciThe difference from \ref pcm_plugins_dshare "dshare plugin" is that 1567d5ac70f0Sopenharmony_cishare plugin requires the server program "aserver", while dshare plugin 1568d5ac70f0Sopenharmony_cidoesn't need the explicit server but access to the shared buffer. 1569d5ac70f0Sopenharmony_ci 1570d5ac70f0Sopenharmony_ci\code 1571d5ac70f0Sopenharmony_cipcm.name { 1572d5ac70f0Sopenharmony_ci type share # Share PCM 1573d5ac70f0Sopenharmony_ci slave STR # Slave name 1574d5ac70f0Sopenharmony_ci # or 1575d5ac70f0Sopenharmony_ci slave { # Slave definition 1576d5ac70f0Sopenharmony_ci pcm STR # Slave PCM name 1577d5ac70f0Sopenharmony_ci [format STR] # Slave format 1578d5ac70f0Sopenharmony_ci [channels INT] # Slave channels 1579d5ac70f0Sopenharmony_ci [rate INT] # Slave rate 1580d5ac70f0Sopenharmony_ci [period_time INT] # Slave period time in us 1581d5ac70f0Sopenharmony_ci [buffer_time INT] # Slave buffer time in us 1582d5ac70f0Sopenharmony_ci } 1583d5ac70f0Sopenharmony_ci bindings { 1584d5ac70f0Sopenharmony_ci N INT # Slave channel INT for client channel N 1585d5ac70f0Sopenharmony_ci } 1586d5ac70f0Sopenharmony_ci} 1587d5ac70f0Sopenharmony_ci\endcode 1588d5ac70f0Sopenharmony_ci 1589d5ac70f0Sopenharmony_ci\subsection pcm_plugins_share_funcref Function reference 1590d5ac70f0Sopenharmony_ci 1591d5ac70f0Sopenharmony_ci<UL> 1592d5ac70f0Sopenharmony_ci <LI>snd_pcm_share_open() 1593d5ac70f0Sopenharmony_ci <LI>_snd_pcm_share_open() 1594d5ac70f0Sopenharmony_ci</UL> 1595d5ac70f0Sopenharmony_ci 1596d5ac70f0Sopenharmony_ci*/ 1597d5ac70f0Sopenharmony_ci 1598d5ac70f0Sopenharmony_ci/** 1599d5ac70f0Sopenharmony_ci * \brief Creates a new Share PCM 1600d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 1601d5ac70f0Sopenharmony_ci * \param name Name of PCM 1602d5ac70f0Sopenharmony_ci * \param root Root configuration node 1603d5ac70f0Sopenharmony_ci * \param conf Configuration node with Share PCM description 1604d5ac70f0Sopenharmony_ci * \param stream Stream type 1605d5ac70f0Sopenharmony_ci * \param mode Stream mode 1606d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 1607d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 1608d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 1609d5ac70f0Sopenharmony_ci * changed in future. 1610d5ac70f0Sopenharmony_ci */ 1611d5ac70f0Sopenharmony_ciint _snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, 1612d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *conf, 1613d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 1614d5ac70f0Sopenharmony_ci{ 1615d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 1616d5ac70f0Sopenharmony_ci const char *sname = NULL; 1617d5ac70f0Sopenharmony_ci snd_config_t *bindings = NULL; 1618d5ac70f0Sopenharmony_ci int err; 1619d5ac70f0Sopenharmony_ci snd_config_t *slave = NULL, *sconf; 1620d5ac70f0Sopenharmony_ci unsigned int *channels_map = NULL; 1621d5ac70f0Sopenharmony_ci unsigned int channels = 0; 1622d5ac70f0Sopenharmony_ci snd_pcm_format_t sformat = SND_PCM_FORMAT_UNKNOWN; 1623d5ac70f0Sopenharmony_ci int schannels = -1; 1624d5ac70f0Sopenharmony_ci int srate = -1; 1625d5ac70f0Sopenharmony_ci int speriod_time= -1, sbuffer_time = -1; 1626d5ac70f0Sopenharmony_ci unsigned int schannel_max = 0; 1627d5ac70f0Sopenharmony_ci 1628d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 1629d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 1630d5ac70f0Sopenharmony_ci const char *id; 1631d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1632d5ac70f0Sopenharmony_ci continue; 1633d5ac70f0Sopenharmony_ci if (snd_pcm_conf_generic_id(id)) 1634d5ac70f0Sopenharmony_ci continue; 1635d5ac70f0Sopenharmony_ci if (strcmp(id, "slave") == 0) { 1636d5ac70f0Sopenharmony_ci slave = n; 1637d5ac70f0Sopenharmony_ci continue; 1638d5ac70f0Sopenharmony_ci } 1639d5ac70f0Sopenharmony_ci if (strcmp(id, "bindings") == 0) { 1640d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 1641d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 1642d5ac70f0Sopenharmony_ci return -EINVAL; 1643d5ac70f0Sopenharmony_ci } 1644d5ac70f0Sopenharmony_ci bindings = n; 1645d5ac70f0Sopenharmony_ci continue; 1646d5ac70f0Sopenharmony_ci } 1647d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 1648d5ac70f0Sopenharmony_ci return -EINVAL; 1649d5ac70f0Sopenharmony_ci } 1650d5ac70f0Sopenharmony_ci if (!slave) { 1651d5ac70f0Sopenharmony_ci SNDERR("slave is not defined"); 1652d5ac70f0Sopenharmony_ci return -EINVAL; 1653d5ac70f0Sopenharmony_ci } 1654d5ac70f0Sopenharmony_ci err = snd_pcm_slave_conf(root, slave, &sconf, 5, 1655d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_FORMAT, 0, &sformat, 1656d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_CHANNELS, 0, &schannels, 1657d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_RATE, 0, &srate, 1658d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_PERIOD_TIME, 0, &speriod_time, 1659d5ac70f0Sopenharmony_ci SND_PCM_HW_PARAM_BUFFER_TIME, 0, &sbuffer_time); 1660d5ac70f0Sopenharmony_ci if (err < 0) 1661d5ac70f0Sopenharmony_ci return err; 1662d5ac70f0Sopenharmony_ci 1663d5ac70f0Sopenharmony_ci /* FIXME: nothing strictly forces to have named definition */ 1664d5ac70f0Sopenharmony_ci err = snd_config_get_string(sconf, &sname); 1665d5ac70f0Sopenharmony_ci sname = err >= 0 && sname ? strdup(sname) : NULL; 1666d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 1667d5ac70f0Sopenharmony_ci if (sname == NULL) { 1668d5ac70f0Sopenharmony_ci SNDERR("slave.pcm is not a string"); 1669d5ac70f0Sopenharmony_ci return err; 1670d5ac70f0Sopenharmony_ci } 1671d5ac70f0Sopenharmony_ci 1672d5ac70f0Sopenharmony_ci if (!bindings) { 1673d5ac70f0Sopenharmony_ci SNDERR("bindings is not defined"); 1674d5ac70f0Sopenharmony_ci err = -EINVAL; 1675d5ac70f0Sopenharmony_ci goto _free; 1676d5ac70f0Sopenharmony_ci } 1677d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, bindings) { 1678d5ac70f0Sopenharmony_ci long cchannel = -1; 1679d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 1680d5ac70f0Sopenharmony_ci const char *id; 1681d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1682d5ac70f0Sopenharmony_ci continue; 1683d5ac70f0Sopenharmony_ci err = safe_strtol(id, &cchannel); 1684d5ac70f0Sopenharmony_ci if (err < 0 || cchannel < 0) { 1685d5ac70f0Sopenharmony_ci SNDERR("Invalid client channel in binding: %s", id); 1686d5ac70f0Sopenharmony_ci err = -EINVAL; 1687d5ac70f0Sopenharmony_ci goto _free; 1688d5ac70f0Sopenharmony_ci } 1689d5ac70f0Sopenharmony_ci if ((unsigned)cchannel >= channels) 1690d5ac70f0Sopenharmony_ci channels = cchannel + 1; 1691d5ac70f0Sopenharmony_ci } 1692d5ac70f0Sopenharmony_ci if (channels == 0) { 1693d5ac70f0Sopenharmony_ci SNDERR("No bindings defined"); 1694d5ac70f0Sopenharmony_ci err = -EINVAL; 1695d5ac70f0Sopenharmony_ci goto _free; 1696d5ac70f0Sopenharmony_ci } 1697d5ac70f0Sopenharmony_ci channels_map = calloc(channels, sizeof(*channels_map)); 1698d5ac70f0Sopenharmony_ci if (! channels_map) { 1699d5ac70f0Sopenharmony_ci err = -ENOMEM; 1700d5ac70f0Sopenharmony_ci goto _free; 1701d5ac70f0Sopenharmony_ci } 1702d5ac70f0Sopenharmony_ci 1703d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, bindings) { 1704d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 1705d5ac70f0Sopenharmony_ci const char *id; 1706d5ac70f0Sopenharmony_ci long cchannel; 1707d5ac70f0Sopenharmony_ci long schannel = -1; 1708d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 1709d5ac70f0Sopenharmony_ci continue; 1710d5ac70f0Sopenharmony_ci cchannel = atoi(id); 1711d5ac70f0Sopenharmony_ci err = snd_config_get_integer(n, &schannel); 1712d5ac70f0Sopenharmony_ci if (err < 0) { 1713d5ac70f0Sopenharmony_ci goto _free; 1714d5ac70f0Sopenharmony_ci } 1715d5ac70f0Sopenharmony_ci assert(schannel >= 0); 1716d5ac70f0Sopenharmony_ci assert(schannels <= 0 || schannel < schannels); 1717d5ac70f0Sopenharmony_ci channels_map[cchannel] = schannel; 1718d5ac70f0Sopenharmony_ci if ((unsigned)schannel > schannel_max) 1719d5ac70f0Sopenharmony_ci schannel_max = schannel; 1720d5ac70f0Sopenharmony_ci } 1721d5ac70f0Sopenharmony_ci if (schannels <= 0) 1722d5ac70f0Sopenharmony_ci schannels = schannel_max + 1; 1723d5ac70f0Sopenharmony_ci err = snd_pcm_share_open(pcmp, name, sname, sformat, srate, 1724d5ac70f0Sopenharmony_ci (unsigned int) schannels, 1725d5ac70f0Sopenharmony_ci speriod_time, sbuffer_time, 1726d5ac70f0Sopenharmony_ci channels, channels_map, stream, mode); 1727d5ac70f0Sopenharmony_ci_free: 1728d5ac70f0Sopenharmony_ci free(channels_map); 1729d5ac70f0Sopenharmony_ci free((char *)sname); 1730d5ac70f0Sopenharmony_ci return err; 1731d5ac70f0Sopenharmony_ci} 1732d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 1733d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_share_open, SND_PCM_DLSYM_VERSION); 1734d5ac70f0Sopenharmony_ci#endif 1735