📄 adin_mic_linux_alsa.c
字号:
return(FALSE); } if ((minsize = snd_pcm_hw_params_get_period_size_min(hwparams, &dir)) < 0) { jlog("Error: adin_alsa: cannot get minimum period size\n"); return(FALSE); }#else has_current_period = TRUE; if ((err = snd_pcm_hw_params_get_period_time(hwparams, &period_time_current, &dir)) < 0) { has_current_period = FALSE; } if (has_current_period) { jlog("Stat: adin_alsa: current latency time: %d msec\n", period_time_current / 1000); }#endif /* set period time (near value will be used) */#if (SND_LIB_MAJOR == 0) periodsize = actual_rate * latency / 1000 * sizeof(SP16); if (periodsize < minsize) { jlog("Stat: adin_alsa: PCM latency of %d ms (%d bytes) too small, use device minimum %d bytes\n", latency, periodsize, minsize); periodsize = minsize; } else if (periodsize > maxsize) { jlog("Stat: adin_alsa: PCM latency of %d ms (%d bytes) too large, use device maximum %d bytes\n", latency, periodsize, maxsize); periodsize = maxsize; } actual_size = snd_pcm_hw_params_set_period_size_near(handle, hwparams, periodsize, &dir); if (actual_size < 0) { jlog("Error: adin_alsa: cannot set PCM record period size to %d (%s)\n", periodsize, snd_strerror(actual_size)); return(FALSE); } if (actual_size != periodsize) { jlog("Stat: adin_alsa: PCM period size: %d bytes (%dms) -> %d bytes\n", periodsize, latency, actual_size); } jlog("Stat: Audio I/O Latency = %d msec (data fragment = %d frames)\n", actual_size * 1000 / (actual_rate * sizeof(SP16)), actual_size / sizeof(SP16));#else period_time = latency * 1000; if (!force && has_current_period && period_time > period_time_current) { jlog("Stat: adin_alsa: current latency (%dms) is shorter than %dms, leave it\n", period_time_current / 1000, latency); period_time = period_time_current; } else { if ((err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0)) < 0) { jlog("Error: adin_alsa: cannot set PCM record period time to %d msec (%s)\n", period_time / 1000, snd_strerror(err)); return(FALSE); } snd_pcm_hw_params_get_period_size(hwparams, &chunk_size, 0); jlog("Stat: adin_alsa: latency set to %d msec (chunk = %d bytes)\n", period_time / 1000, chunk_size); }#endif#if (SND_LIB_MAJOR == 0) /* set number of periods ( = 2) */ if ((err = snd_pcm_hw_params_set_periods(handle, hwparams, sizeof(SP16), 0)) < 0) { jlog("Error: adin_alsa: cannot set PCM number of periods to %d (%s)\n", sizeof(SP16), snd_strerror(err)); return(FALSE); }#endif } /* apply the configuration to the PCM device */ if ((err = snd_pcm_hw_params(handle, hwparams)) < 0) { jlog("Error: adin_alsa: cannot set PCM hardware parameters (%s)\n", snd_strerror(err)); return(FALSE); } /* prepare for recording */ if ((err = snd_pcm_prepare(handle)) < 0) { jlog("Error: adin_alsa: failed to prepare audio interface (%s)\n", snd_strerror(err)); }#if (SND_LIB_MAJOR == 0) /* prepare for polling */ count = snd_pcm_poll_descriptors_count(handle); if (count <= 0) { jlog("Error: adin_alsa: invalid PCM poll descriptors count\n"); return(FALSE); } ufds = mymalloc(sizeof(struct pollfd) * count); if ((err = snd_pcm_poll_descriptors(handle, ufds, count)) < 0) { jlog("Error: adin_alsa: unable to obtain poll descriptors for PCM recording (%s)\n", snd_strerror(err)); return(FALSE); }#endif /* output status */ output_card_info(pcm_name, handle); return(TRUE);#endif /* HAS_ALSA */}#ifdef HAS_ALSA/** * Error recovery when PCM buffer underrun or suspend. * * @param handle [in] audio handler * @param err [in] error code * * @return 0 on success, otherwise the given errno. */static intxrun_recovery(snd_pcm_t *handle, int err){ if (err == -EPIPE) { /* under-run */ err = snd_pcm_prepare(handle); if (err < 0) jlog("Error: adin_alsa: can't recovery from PCM buffer underrun, prepare failed: %s\n", snd_strerror(err)); return 0; } else if (err == -ESTRPIPE) { while ((err = snd_pcm_resume(handle)) == -EAGAIN) sleep(1); /* wait until the suspend flag is released */ if (err < 0) { err = snd_pcm_prepare(handle); if (err < 0) jlog("Error: adin_alsa: can't recovery from PCM buffer suspend, prepare failed: %s\n", snd_strerror(err)); } return 0; } return err;}#endif /* HAS_ALSA *//** * Start recording. * * @return TRUE on success, FALSE on failure. */booleanadin_alsa_begin(){#ifndef HAS_ALSA return FALSE;#else int err; snd_pcm_state_t status; /* check hardware status */ while(1) { /* wait till prepared */ status = snd_pcm_state(handle); switch(status) { case SND_PCM_STATE_PREPARED: /* prepared for operation */ if ((err = snd_pcm_start(handle)) < 0) { jlog("Error: adin_alsa: cannot start PCM (%s)\n", snd_strerror(err)); return (FALSE); } return(TRUE); break; case SND_PCM_STATE_RUNNING: /* capturing the samples of other application */ if ((err = snd_pcm_drop(handle)) < 0) { /* discard the existing samples */ jlog("Error: adin_alsa: cannot drop PCM (%s)\n", snd_strerror(err)); return (FALSE); } break; case SND_PCM_STATE_XRUN: /* buffer overrun */ if ((err = xrun_recovery(handle, -EPIPE)) < 0) { jlog("Error: adin_alsa: PCM XRUN recovery failed (%s)\n", snd_strerror(err)); return(FALSE); } break; case SND_PCM_STATE_SUSPENDED: /* suspended by power management system */ if ((err = xrun_recovery(handle, -ESTRPIPE)) < 0) { jlog("Error: adin_alsa: PCM XRUN recovery failed (%s)\n", snd_strerror(err)); return(FALSE); } break; default: /* do nothing */ break; } } return(TRUE);#endif /* HAS_ALSA */} /** * Stop recording. * * @return TRUE on success, FALSE on failure. */booleanadin_alsa_end(){ return(TRUE);}/** * @brief Read samples from device * * Try to read @a sampnum samples and returns actual number of recorded * samples currently available. This function will block until * at least one sample can be obtained. * * @param buf [out] samples obtained in this function * @param sampnum [in] wanted number of samples to be read * * @return actural number of read samples, -2 if an error occured. */intadin_alsa_read(SP16 *buf, int sampnum){#ifndef HAS_ALSA return -2;#else int cnt;#if (SND_LIB_MAJOR == 0) snd_pcm_sframes_t avail; while ((avail = snd_pcm_avail_update(handle)) <= 0) { usleep(latency * 1000); } if (avail < sampnum) { cnt = snd_pcm_readi(handle, buf, avail); } else { cnt = snd_pcm_readi(handle, buf, sampnum); }#else int ret; snd_pcm_status_t *status; int res; struct timeval now, diff, tstamp; ret = snd_pcm_wait(handle, MAXPOLLINTERVAL); switch (ret) { case 0: /* timeout */ jlog("Warning: adin_alsa: no data fragment after %d msec?\n", MAXPOLLINTERVAL); cnt = 0; break; case 1: /* has data */ cnt = snd_pcm_readi(handle, buf, sampnum); /* read available (non-block) */ break; case -EPIPE: /* pipe error */ /* try to recover the broken pipe */ snd_pcm_status_alloca(&status); if ((res = snd_pcm_status(handle, status))<0) { jlog("Error: adin_alsa: broken pipe: status error (%s)\n", snd_strerror(res)); return -2; } if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { gettimeofday(&now, 0); snd_pcm_status_get_trigger_tstamp(status, &tstamp); timersub(&now, &tstamp, &diff); jlog("Warning: adin_alsa: overrun!!! (at least %.3f ms long)\n", diff.tv_sec * 1000 + diff.tv_usec / 1000.0); if ((res = snd_pcm_prepare(handle))<0) { jlog("Error: adin_alsa: overrun: prepare error (%s)", snd_strerror(res)); return -2; } break; /* ok, data should be accepted again */ } else if (snd_pcm_status_get_state(status) == SND_PCM_STATE_DRAINING) { jlog("Warning: adin_alsa: draining: capture stream format change? attempting recover...\n"); if ((res = snd_pcm_prepare(handle))<0) { jlog("Error: adin_alsa: draining: prepare error (%s)", snd_strerror(res)); return -2; } break; } jlog("Error: adin_alsa: error in snd_pcm_wait() (%s)\n", snd_pcm_state_name(snd_pcm_status_get_state(status))); return -2; default: /* other poll error */ jlog("Error: adin_alsa: error in snd_pcm_wait() (%s)\n", snd_strerror(ret)); return(-2); /* error */ }#endif if (cnt < 0) { jlog("Error: adin_alsa: failed to read PCM (%s)\n", snd_strerror(cnt)); return(-2); } if (need_swap) { swap_sample_bytes(buf, cnt); } return(cnt);#endif /* HAS_ALSA */}/* end of file */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -