1c72fcc34Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 2c72fcc34Sopenharmony_ci// 3c72fcc34Sopenharmony_ci// xfer-libasound-irq-rw.c - IRQ-based scheduling model for read/write operation. 4c72fcc34Sopenharmony_ci// 5c72fcc34Sopenharmony_ci// Copyright (c) 2018 Takashi Sakamoto <o-takashi@sakamocchi.jp> 6c72fcc34Sopenharmony_ci// 7c72fcc34Sopenharmony_ci// Licensed under the terms of the GNU General Public License, version 2. 8c72fcc34Sopenharmony_ci 9c72fcc34Sopenharmony_ci#include "xfer-libasound.h" 10c72fcc34Sopenharmony_ci#include "misc.h" 11c72fcc34Sopenharmony_ci#include "frame-cache.h" 12c72fcc34Sopenharmony_ci 13c72fcc34Sopenharmony_cistruct rw_closure { 14c72fcc34Sopenharmony_ci snd_pcm_access_t access; 15c72fcc34Sopenharmony_ci int (*process_frames)(struct libasound_state *state, 16c72fcc34Sopenharmony_ci snd_pcm_state_t status, unsigned int *frame_count, 17c72fcc34Sopenharmony_ci struct mapper_context *mapper, 18c72fcc34Sopenharmony_ci struct container_context *cntrs); 19c72fcc34Sopenharmony_ci struct frame_cache cache; 20c72fcc34Sopenharmony_ci}; 21c72fcc34Sopenharmony_ci 22c72fcc34Sopenharmony_cistatic int wait_for_avail(struct libasound_state *state) 23c72fcc34Sopenharmony_ci{ 24c72fcc34Sopenharmony_ci unsigned int msec_per_buffer; 25c72fcc34Sopenharmony_ci unsigned short revents; 26c72fcc34Sopenharmony_ci unsigned short event; 27c72fcc34Sopenharmony_ci int err; 28c72fcc34Sopenharmony_ci 29c72fcc34Sopenharmony_ci // Wait during msec equivalent to all audio data frames in buffer 30c72fcc34Sopenharmony_ci // instead of period, for safe. 31c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_buffer_time(state->hw_params, 32c72fcc34Sopenharmony_ci &msec_per_buffer, NULL); 33c72fcc34Sopenharmony_ci if (err < 0) 34c72fcc34Sopenharmony_ci return err; 35c72fcc34Sopenharmony_ci msec_per_buffer /= 1000; 36c72fcc34Sopenharmony_ci 37c72fcc34Sopenharmony_ci // Wait for hardware IRQ when no available space. 38c72fcc34Sopenharmony_ci err = xfer_libasound_wait_event(state, msec_per_buffer, &revents); 39c72fcc34Sopenharmony_ci if (err < 0) 40c72fcc34Sopenharmony_ci return err; 41c72fcc34Sopenharmony_ci 42c72fcc34Sopenharmony_ci // TODO: error reporting. 43c72fcc34Sopenharmony_ci if (revents & POLLERR) 44c72fcc34Sopenharmony_ci return -EIO; 45c72fcc34Sopenharmony_ci 46c72fcc34Sopenharmony_ci if (snd_pcm_stream(state->handle) == SND_PCM_STREAM_CAPTURE) 47c72fcc34Sopenharmony_ci event = POLLIN; 48c72fcc34Sopenharmony_ci else 49c72fcc34Sopenharmony_ci event = POLLOUT; 50c72fcc34Sopenharmony_ci 51c72fcc34Sopenharmony_ci if (!(revents & event)) 52c72fcc34Sopenharmony_ci return -EAGAIN; 53c72fcc34Sopenharmony_ci 54c72fcc34Sopenharmony_ci return 0; 55c72fcc34Sopenharmony_ci} 56c72fcc34Sopenharmony_ci 57c72fcc34Sopenharmony_cistatic int read_frames(struct libasound_state *state, unsigned int *frame_count, 58c72fcc34Sopenharmony_ci unsigned int avail_count, struct mapper_context *mapper, 59c72fcc34Sopenharmony_ci struct container_context *cntrs) 60c72fcc34Sopenharmony_ci{ 61c72fcc34Sopenharmony_ci struct rw_closure *closure = state->private_data; 62c72fcc34Sopenharmony_ci snd_pcm_sframes_t handled_frame_count; 63c72fcc34Sopenharmony_ci unsigned int consumed_count; 64c72fcc34Sopenharmony_ci int err; 65c72fcc34Sopenharmony_ci 66c72fcc34Sopenharmony_ci // Trim according up to expected frame count. 67c72fcc34Sopenharmony_ci if (*frame_count < avail_count) 68c72fcc34Sopenharmony_ci avail_count = *frame_count; 69c72fcc34Sopenharmony_ci 70c72fcc34Sopenharmony_ci // Cache required amount of frames. 71c72fcc34Sopenharmony_ci if (avail_count > frame_cache_get_count(&closure->cache)) { 72c72fcc34Sopenharmony_ci avail_count -= frame_cache_get_count(&closure->cache); 73c72fcc34Sopenharmony_ci 74c72fcc34Sopenharmony_ci // Execute write operation according to the shape of buffer. 75c72fcc34Sopenharmony_ci // These operations automatically start the substream. 76c72fcc34Sopenharmony_ci if (closure->access == SND_PCM_ACCESS_RW_INTERLEAVED) { 77c72fcc34Sopenharmony_ci handled_frame_count = snd_pcm_readi(state->handle, 78c72fcc34Sopenharmony_ci closure->cache.buf_ptr, 79c72fcc34Sopenharmony_ci avail_count); 80c72fcc34Sopenharmony_ci } else { 81c72fcc34Sopenharmony_ci handled_frame_count = snd_pcm_readn(state->handle, 82c72fcc34Sopenharmony_ci closure->cache.buf_ptr, 83c72fcc34Sopenharmony_ci avail_count); 84c72fcc34Sopenharmony_ci } 85c72fcc34Sopenharmony_ci if (handled_frame_count < 0) { 86c72fcc34Sopenharmony_ci err = handled_frame_count; 87c72fcc34Sopenharmony_ci return err; 88c72fcc34Sopenharmony_ci } 89c72fcc34Sopenharmony_ci frame_cache_increase_count(&closure->cache, handled_frame_count); 90c72fcc34Sopenharmony_ci avail_count = frame_cache_get_count(&closure->cache); 91c72fcc34Sopenharmony_ci } 92c72fcc34Sopenharmony_ci 93c72fcc34Sopenharmony_ci // Write out to file descriptors. 94c72fcc34Sopenharmony_ci consumed_count = avail_count; 95c72fcc34Sopenharmony_ci err = mapper_context_process_frames(mapper, closure->cache.buf, 96c72fcc34Sopenharmony_ci &consumed_count, cntrs); 97c72fcc34Sopenharmony_ci if (err < 0) 98c72fcc34Sopenharmony_ci return err; 99c72fcc34Sopenharmony_ci 100c72fcc34Sopenharmony_ci frame_cache_reduce(&closure->cache, consumed_count); 101c72fcc34Sopenharmony_ci 102c72fcc34Sopenharmony_ci *frame_count = consumed_count; 103c72fcc34Sopenharmony_ci 104c72fcc34Sopenharmony_ci return 0; 105c72fcc34Sopenharmony_ci} 106c72fcc34Sopenharmony_ci 107c72fcc34Sopenharmony_cistatic int r_process_frames_blocking(struct libasound_state *state, 108c72fcc34Sopenharmony_ci snd_pcm_state_t status, 109c72fcc34Sopenharmony_ci unsigned int *frame_count, 110c72fcc34Sopenharmony_ci struct mapper_context *mapper, 111c72fcc34Sopenharmony_ci struct container_context *cntrs) 112c72fcc34Sopenharmony_ci{ 113c72fcc34Sopenharmony_ci snd_pcm_sframes_t avail; 114c72fcc34Sopenharmony_ci snd_pcm_uframes_t avail_count; 115c72fcc34Sopenharmony_ci int err = 0; 116c72fcc34Sopenharmony_ci 117c72fcc34Sopenharmony_ci if (status == SND_PCM_STATE_RUNNING) { 118c72fcc34Sopenharmony_ci // Check available space on the buffer. 119c72fcc34Sopenharmony_ci avail = snd_pcm_avail(state->handle); 120c72fcc34Sopenharmony_ci if (avail < 0) { 121c72fcc34Sopenharmony_ci err = avail; 122c72fcc34Sopenharmony_ci goto error; 123c72fcc34Sopenharmony_ci } 124c72fcc34Sopenharmony_ci avail_count = (snd_pcm_uframes_t)avail; 125c72fcc34Sopenharmony_ci 126c72fcc34Sopenharmony_ci if (avail_count == 0) { 127c72fcc34Sopenharmony_ci // Request data frames so that blocking is just 128c72fcc34Sopenharmony_ci // released. 129c72fcc34Sopenharmony_ci err = snd_pcm_sw_params_get_avail_min(state->sw_params, 130c72fcc34Sopenharmony_ci &avail_count); 131c72fcc34Sopenharmony_ci if (err < 0) 132c72fcc34Sopenharmony_ci goto error; 133c72fcc34Sopenharmony_ci } 134c72fcc34Sopenharmony_ci } else { 135c72fcc34Sopenharmony_ci // Request data frames so that the PCM substream starts. 136c72fcc34Sopenharmony_ci snd_pcm_uframes_t frame_count; 137c72fcc34Sopenharmony_ci err = snd_pcm_sw_params_get_start_threshold(state->sw_params, 138c72fcc34Sopenharmony_ci &frame_count); 139c72fcc34Sopenharmony_ci if (err < 0) 140c72fcc34Sopenharmony_ci goto error; 141c72fcc34Sopenharmony_ci 142c72fcc34Sopenharmony_ci avail_count = (unsigned int)frame_count; 143c72fcc34Sopenharmony_ci } 144c72fcc34Sopenharmony_ci 145c72fcc34Sopenharmony_ci err = read_frames(state, frame_count, avail_count, mapper, cntrs); 146c72fcc34Sopenharmony_ci if (err < 0) 147c72fcc34Sopenharmony_ci goto error; 148c72fcc34Sopenharmony_ci 149c72fcc34Sopenharmony_ci return 0; 150c72fcc34Sopenharmony_cierror: 151c72fcc34Sopenharmony_ci *frame_count = 0; 152c72fcc34Sopenharmony_ci return err; 153c72fcc34Sopenharmony_ci} 154c72fcc34Sopenharmony_ci 155c72fcc34Sopenharmony_cistatic int r_process_frames_nonblocking(struct libasound_state *state, 156c72fcc34Sopenharmony_ci snd_pcm_state_t status, 157c72fcc34Sopenharmony_ci unsigned int *frame_count, 158c72fcc34Sopenharmony_ci struct mapper_context *mapper, 159c72fcc34Sopenharmony_ci struct container_context *cntrs) 160c72fcc34Sopenharmony_ci{ 161c72fcc34Sopenharmony_ci snd_pcm_sframes_t avail; 162c72fcc34Sopenharmony_ci snd_pcm_uframes_t avail_count; 163c72fcc34Sopenharmony_ci int err = 0; 164c72fcc34Sopenharmony_ci 165c72fcc34Sopenharmony_ci if (status != SND_PCM_STATE_RUNNING) { 166c72fcc34Sopenharmony_ci err = snd_pcm_start(state->handle); 167c72fcc34Sopenharmony_ci if (err < 0) 168c72fcc34Sopenharmony_ci goto error; 169c72fcc34Sopenharmony_ci } 170c72fcc34Sopenharmony_ci 171c72fcc34Sopenharmony_ci if (state->use_waiter) { 172c72fcc34Sopenharmony_ci err = wait_for_avail(state); 173c72fcc34Sopenharmony_ci if (err < 0) 174c72fcc34Sopenharmony_ci goto error; 175c72fcc34Sopenharmony_ci } 176c72fcc34Sopenharmony_ci 177c72fcc34Sopenharmony_ci // Check available space on the buffer. 178c72fcc34Sopenharmony_ci avail = snd_pcm_avail(state->handle); 179c72fcc34Sopenharmony_ci if (avail < 0) { 180c72fcc34Sopenharmony_ci err = avail; 181c72fcc34Sopenharmony_ci goto error; 182c72fcc34Sopenharmony_ci } 183c72fcc34Sopenharmony_ci avail_count = (snd_pcm_uframes_t)avail; 184c72fcc34Sopenharmony_ci 185c72fcc34Sopenharmony_ci if (avail_count == 0) { 186c72fcc34Sopenharmony_ci // Let's go to a next iteration. 187c72fcc34Sopenharmony_ci err = 0; 188c72fcc34Sopenharmony_ci goto error; 189c72fcc34Sopenharmony_ci } 190c72fcc34Sopenharmony_ci 191c72fcc34Sopenharmony_ci err = read_frames(state, frame_count, avail_count, mapper, cntrs); 192c72fcc34Sopenharmony_ci if (err < 0) 193c72fcc34Sopenharmony_ci goto error; 194c72fcc34Sopenharmony_ci 195c72fcc34Sopenharmony_ci return 0; 196c72fcc34Sopenharmony_cierror: 197c72fcc34Sopenharmony_ci *frame_count = 0; 198c72fcc34Sopenharmony_ci return err; 199c72fcc34Sopenharmony_ci} 200c72fcc34Sopenharmony_ci 201c72fcc34Sopenharmony_cistatic int write_frames(struct libasound_state *state, 202c72fcc34Sopenharmony_ci unsigned int *frame_count, unsigned int avail_count, 203c72fcc34Sopenharmony_ci struct mapper_context *mapper, 204c72fcc34Sopenharmony_ci struct container_context *cntrs) 205c72fcc34Sopenharmony_ci{ 206c72fcc34Sopenharmony_ci struct rw_closure *closure = state->private_data; 207c72fcc34Sopenharmony_ci snd_pcm_uframes_t consumed_count; 208c72fcc34Sopenharmony_ci snd_pcm_sframes_t handled_frame_count; 209c72fcc34Sopenharmony_ci int err; 210c72fcc34Sopenharmony_ci 211c72fcc34Sopenharmony_ci // Trim according up to expected frame count. 212c72fcc34Sopenharmony_ci if (*frame_count < avail_count) 213c72fcc34Sopenharmony_ci avail_count = *frame_count; 214c72fcc34Sopenharmony_ci 215c72fcc34Sopenharmony_ci // Cache required amount of frames. 216c72fcc34Sopenharmony_ci if (avail_count > frame_cache_get_count(&closure->cache)) { 217c72fcc34Sopenharmony_ci avail_count -= frame_cache_get_count(&closure->cache); 218c72fcc34Sopenharmony_ci 219c72fcc34Sopenharmony_ci // Read frames to transfer. 220c72fcc34Sopenharmony_ci err = mapper_context_process_frames(mapper, 221c72fcc34Sopenharmony_ci closure->cache.buf_ptr, &avail_count, cntrs); 222c72fcc34Sopenharmony_ci if (err < 0) 223c72fcc34Sopenharmony_ci return err; 224c72fcc34Sopenharmony_ci frame_cache_increase_count(&closure->cache, avail_count); 225c72fcc34Sopenharmony_ci avail_count = frame_cache_get_count(&closure->cache); 226c72fcc34Sopenharmony_ci } 227c72fcc34Sopenharmony_ci 228c72fcc34Sopenharmony_ci // Execute write operation according to the shape of buffer. These 229c72fcc34Sopenharmony_ci // operations automatically start the stream. 230c72fcc34Sopenharmony_ci consumed_count = avail_count; 231c72fcc34Sopenharmony_ci if (closure->access == SND_PCM_ACCESS_RW_INTERLEAVED) { 232c72fcc34Sopenharmony_ci handled_frame_count = snd_pcm_writei(state->handle, 233c72fcc34Sopenharmony_ci closure->cache.buf, consumed_count); 234c72fcc34Sopenharmony_ci } else { 235c72fcc34Sopenharmony_ci handled_frame_count = snd_pcm_writen(state->handle, 236c72fcc34Sopenharmony_ci closure->cache.buf, consumed_count); 237c72fcc34Sopenharmony_ci } 238c72fcc34Sopenharmony_ci if (handled_frame_count < 0) { 239c72fcc34Sopenharmony_ci err = handled_frame_count; 240c72fcc34Sopenharmony_ci return err; 241c72fcc34Sopenharmony_ci } 242c72fcc34Sopenharmony_ci 243c72fcc34Sopenharmony_ci consumed_count = handled_frame_count; 244c72fcc34Sopenharmony_ci frame_cache_reduce(&closure->cache, consumed_count); 245c72fcc34Sopenharmony_ci 246c72fcc34Sopenharmony_ci *frame_count = consumed_count; 247c72fcc34Sopenharmony_ci 248c72fcc34Sopenharmony_ci return 0; 249c72fcc34Sopenharmony_ci} 250c72fcc34Sopenharmony_ci 251c72fcc34Sopenharmony_cistatic int w_process_frames_blocking(struct libasound_state *state, 252c72fcc34Sopenharmony_ci snd_pcm_state_t status, 253c72fcc34Sopenharmony_ci unsigned int *frame_count, 254c72fcc34Sopenharmony_ci struct mapper_context *mapper, 255c72fcc34Sopenharmony_ci struct container_context *cntrs) 256c72fcc34Sopenharmony_ci{ 257c72fcc34Sopenharmony_ci snd_pcm_sframes_t avail; 258c72fcc34Sopenharmony_ci unsigned int avail_count; 259c72fcc34Sopenharmony_ci int err; 260c72fcc34Sopenharmony_ci 261c72fcc34Sopenharmony_ci if (status == SND_PCM_STATE_RUNNING) { 262c72fcc34Sopenharmony_ci // Check available space on the buffer. 263c72fcc34Sopenharmony_ci avail = snd_pcm_avail(state->handle); 264c72fcc34Sopenharmony_ci if (avail < 0) { 265c72fcc34Sopenharmony_ci err = avail; 266c72fcc34Sopenharmony_ci goto error; 267c72fcc34Sopenharmony_ci } 268c72fcc34Sopenharmony_ci avail_count = (unsigned int)avail; 269c72fcc34Sopenharmony_ci 270c72fcc34Sopenharmony_ci if (avail_count == 0) { 271c72fcc34Sopenharmony_ci // Fill with data frames so that blocking is just 272c72fcc34Sopenharmony_ci // released. 273c72fcc34Sopenharmony_ci snd_pcm_uframes_t avail_min; 274c72fcc34Sopenharmony_ci err = snd_pcm_sw_params_get_avail_min(state->sw_params, 275c72fcc34Sopenharmony_ci &avail_min); 276c72fcc34Sopenharmony_ci if (err < 0) 277c72fcc34Sopenharmony_ci goto error; 278c72fcc34Sopenharmony_ci avail_count = (unsigned int)avail_min; 279c72fcc34Sopenharmony_ci } 280c72fcc34Sopenharmony_ci } else { 281c72fcc34Sopenharmony_ci snd_pcm_uframes_t frames_for_start_threshold; 282c72fcc34Sopenharmony_ci snd_pcm_uframes_t frames_per_period; 283c72fcc34Sopenharmony_ci 284c72fcc34Sopenharmony_ci // Fill with data frames so that the PCM substream starts. 285c72fcc34Sopenharmony_ci err = snd_pcm_sw_params_get_start_threshold(state->sw_params, 286c72fcc34Sopenharmony_ci &frames_for_start_threshold); 287c72fcc34Sopenharmony_ci if (err < 0) 288c72fcc34Sopenharmony_ci goto error; 289c72fcc34Sopenharmony_ci 290c72fcc34Sopenharmony_ci // But the above number can be too small and cause XRUN because 291c72fcc34Sopenharmony_ci // I/O operation is done per period. 292c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_period_size(state->hw_params, 293c72fcc34Sopenharmony_ci &frames_per_period, NULL); 294c72fcc34Sopenharmony_ci if (err < 0) 295c72fcc34Sopenharmony_ci goto error; 296c72fcc34Sopenharmony_ci 297c72fcc34Sopenharmony_ci // Use larger one to prevent from both of XRUN and successive 298c72fcc34Sopenharmony_ci // blocking. 299c72fcc34Sopenharmony_ci if (frames_for_start_threshold > frames_per_period) 300c72fcc34Sopenharmony_ci avail_count = (unsigned int)frames_for_start_threshold; 301c72fcc34Sopenharmony_ci else 302c72fcc34Sopenharmony_ci avail_count = (unsigned int)frames_per_period; 303c72fcc34Sopenharmony_ci } 304c72fcc34Sopenharmony_ci 305c72fcc34Sopenharmony_ci err = write_frames(state, frame_count, avail_count, mapper, cntrs); 306c72fcc34Sopenharmony_ci if (err < 0) 307c72fcc34Sopenharmony_ci goto error; 308c72fcc34Sopenharmony_ci 309c72fcc34Sopenharmony_ci return 0; 310c72fcc34Sopenharmony_cierror: 311c72fcc34Sopenharmony_ci *frame_count = 0; 312c72fcc34Sopenharmony_ci return err; 313c72fcc34Sopenharmony_ci} 314c72fcc34Sopenharmony_ci 315c72fcc34Sopenharmony_cistatic int w_process_frames_nonblocking(struct libasound_state *state, 316c72fcc34Sopenharmony_ci snd_pcm_state_t pcm_state ATTRIBUTE_UNUSED, 317c72fcc34Sopenharmony_ci unsigned int *frame_count, 318c72fcc34Sopenharmony_ci struct mapper_context *mapper, 319c72fcc34Sopenharmony_ci struct container_context *cntrs) 320c72fcc34Sopenharmony_ci{ 321c72fcc34Sopenharmony_ci snd_pcm_sframes_t avail; 322c72fcc34Sopenharmony_ci unsigned int avail_count; 323c72fcc34Sopenharmony_ci int err; 324c72fcc34Sopenharmony_ci 325c72fcc34Sopenharmony_ci if (state->use_waiter) { 326c72fcc34Sopenharmony_ci err = wait_for_avail(state); 327c72fcc34Sopenharmony_ci if (err < 0) 328c72fcc34Sopenharmony_ci goto error; 329c72fcc34Sopenharmony_ci } 330c72fcc34Sopenharmony_ci 331c72fcc34Sopenharmony_ci // Check available space on the buffer. 332c72fcc34Sopenharmony_ci avail = snd_pcm_avail(state->handle); 333c72fcc34Sopenharmony_ci if (avail < 0) { 334c72fcc34Sopenharmony_ci err = avail; 335c72fcc34Sopenharmony_ci goto error; 336c72fcc34Sopenharmony_ci } 337c72fcc34Sopenharmony_ci avail_count = (unsigned int)avail; 338c72fcc34Sopenharmony_ci 339c72fcc34Sopenharmony_ci if (avail_count == 0) { 340c72fcc34Sopenharmony_ci // Let's go to a next iteration. 341c72fcc34Sopenharmony_ci err = 0; 342c72fcc34Sopenharmony_ci goto error; 343c72fcc34Sopenharmony_ci } 344c72fcc34Sopenharmony_ci 345c72fcc34Sopenharmony_ci err = write_frames(state, frame_count, avail_count, mapper, cntrs); 346c72fcc34Sopenharmony_ci if (err < 0) 347c72fcc34Sopenharmony_ci goto error; 348c72fcc34Sopenharmony_ci 349c72fcc34Sopenharmony_ci // NOTE: The substream starts automatically when the accumulated number 350c72fcc34Sopenharmony_ci // of queued data frame exceeds start_threshold. 351c72fcc34Sopenharmony_ci 352c72fcc34Sopenharmony_ci return 0; 353c72fcc34Sopenharmony_cierror: 354c72fcc34Sopenharmony_ci *frame_count = 0; 355c72fcc34Sopenharmony_ci return err; 356c72fcc34Sopenharmony_ci} 357c72fcc34Sopenharmony_ci 358c72fcc34Sopenharmony_cistatic int irq_rw_pre_process(struct libasound_state *state) 359c72fcc34Sopenharmony_ci{ 360c72fcc34Sopenharmony_ci struct rw_closure *closure = state->private_data; 361c72fcc34Sopenharmony_ci snd_pcm_format_t format; 362c72fcc34Sopenharmony_ci snd_pcm_uframes_t frames_per_buffer; 363c72fcc34Sopenharmony_ci int bytes_per_sample; 364c72fcc34Sopenharmony_ci unsigned int samples_per_frame; 365c72fcc34Sopenharmony_ci int err; 366c72fcc34Sopenharmony_ci 367c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_format(state->hw_params, &format); 368c72fcc34Sopenharmony_ci if (err < 0) 369c72fcc34Sopenharmony_ci return err; 370c72fcc34Sopenharmony_ci bytes_per_sample = snd_pcm_format_physical_width(format) / 8; 371c72fcc34Sopenharmony_ci if (bytes_per_sample <= 0) 372c72fcc34Sopenharmony_ci return -ENXIO; 373c72fcc34Sopenharmony_ci 374c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_channels(state->hw_params, 375c72fcc34Sopenharmony_ci &samples_per_frame); 376c72fcc34Sopenharmony_ci if (err < 0) 377c72fcc34Sopenharmony_ci return err; 378c72fcc34Sopenharmony_ci 379c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_buffer_size(state->hw_params, 380c72fcc34Sopenharmony_ci &frames_per_buffer); 381c72fcc34Sopenharmony_ci if (err < 0) 382c72fcc34Sopenharmony_ci return err; 383c72fcc34Sopenharmony_ci 384c72fcc34Sopenharmony_ci err = snd_pcm_hw_params_get_access(state->hw_params, &closure->access); 385c72fcc34Sopenharmony_ci if (err < 0) 386c72fcc34Sopenharmony_ci return err; 387c72fcc34Sopenharmony_ci 388c72fcc34Sopenharmony_ci err = frame_cache_init(&closure->cache, closure->access, 389c72fcc34Sopenharmony_ci bytes_per_sample, samples_per_frame, 390c72fcc34Sopenharmony_ci frames_per_buffer); 391c72fcc34Sopenharmony_ci if (err < 0) 392c72fcc34Sopenharmony_ci return err; 393c72fcc34Sopenharmony_ci 394c72fcc34Sopenharmony_ci if (snd_pcm_stream(state->handle) == SND_PCM_STREAM_CAPTURE) { 395c72fcc34Sopenharmony_ci if (state->nonblock) 396c72fcc34Sopenharmony_ci closure->process_frames = r_process_frames_nonblocking; 397c72fcc34Sopenharmony_ci else 398c72fcc34Sopenharmony_ci closure->process_frames = r_process_frames_blocking; 399c72fcc34Sopenharmony_ci } else { 400c72fcc34Sopenharmony_ci if (state->nonblock) 401c72fcc34Sopenharmony_ci closure->process_frames = w_process_frames_nonblocking; 402c72fcc34Sopenharmony_ci else 403c72fcc34Sopenharmony_ci closure->process_frames = w_process_frames_blocking; 404c72fcc34Sopenharmony_ci } 405c72fcc34Sopenharmony_ci 406c72fcc34Sopenharmony_ci return 0; 407c72fcc34Sopenharmony_ci} 408c72fcc34Sopenharmony_ci 409c72fcc34Sopenharmony_cistatic int irq_rw_process_frames(struct libasound_state *state, 410c72fcc34Sopenharmony_ci unsigned int *frame_count, 411c72fcc34Sopenharmony_ci struct mapper_context *mapper, 412c72fcc34Sopenharmony_ci struct container_context *cntrs) 413c72fcc34Sopenharmony_ci{ 414c72fcc34Sopenharmony_ci struct rw_closure *closure = state->private_data; 415c72fcc34Sopenharmony_ci snd_pcm_state_t status; 416c72fcc34Sopenharmony_ci 417c72fcc34Sopenharmony_ci // Need to recover the stream. 418c72fcc34Sopenharmony_ci status = snd_pcm_state(state->handle); 419c72fcc34Sopenharmony_ci if (status != SND_PCM_STATE_RUNNING && status != SND_PCM_STATE_PREPARED) 420c72fcc34Sopenharmony_ci return -EPIPE; 421c72fcc34Sopenharmony_ci 422c72fcc34Sopenharmony_ci // NOTE: Actually, status can be shift always. 423c72fcc34Sopenharmony_ci return closure->process_frames(state, status, frame_count, mapper, cntrs); 424c72fcc34Sopenharmony_ci} 425c72fcc34Sopenharmony_ci 426c72fcc34Sopenharmony_cistatic void irq_rw_post_process(struct libasound_state *state) 427c72fcc34Sopenharmony_ci{ 428c72fcc34Sopenharmony_ci struct rw_closure *closure = state->private_data; 429c72fcc34Sopenharmony_ci 430c72fcc34Sopenharmony_ci frame_cache_destroy(&closure->cache); 431c72fcc34Sopenharmony_ci} 432c72fcc34Sopenharmony_ci 433c72fcc34Sopenharmony_ciconst struct xfer_libasound_ops xfer_libasound_irq_rw_ops = { 434c72fcc34Sopenharmony_ci .pre_process = irq_rw_pre_process, 435c72fcc34Sopenharmony_ci .process_frames = irq_rw_process_frames, 436c72fcc34Sopenharmony_ci .post_process = irq_rw_post_process, 437c72fcc34Sopenharmony_ci .private_size = sizeof(struct rw_closure), 438c72fcc34Sopenharmony_ci}; 439