#define ALSA_PCM_NEW_HW_PARAMS_API #include #include "audio.h" #include "typedef.h" #define TEMP_BUF_SZ (handle->frames * CHANNELS * 2) #define HANDLE (*(snd_pcm_t**)(handle->h)) #define MIN(a,b) (((a)<(b))?(a):(b)) int audio_create(audio_handle *handle, audio_handle_types t) { handle->h = malloc(sizeof(snd_pcm_t *)); snd_pcm_stream_t type = (t == RECORD) ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK; int rc = snd_pcm_open(handle->h, "default", type, 0); if (rc < 0) { err("unable to open pcm device: %s\n", snd_strerror(rc)); return 1; } int dir; snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(¶ms); // allocate params snd_pcm_hw_params_any(HANDLE, params); // set params snd_pcm_hw_params_set_access(HANDLE, params, SND_PCM_ACCESS_RW_INTERLEAVED); // interleaved mode snd_pcm_hw_params_set_format(HANDLE, params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(HANDLE, params, CHANNELS); unsigned int samp_rate = SAMPLING_RATE; snd_pcm_hw_params_set_rate_near(HANDLE, params, &samp_rate, &dir); snd_pcm_uframes_t frames = FRAMES; snd_pcm_hw_params_set_period_size_near(HANDLE, params, &frames, &dir); rc = snd_pcm_hw_params(HANDLE, params); // write params to handle if (rc < 0) { err("unable to set hw parameters: %s\n", snd_strerror(rc)); return 1; } snd_pcm_hw_params_get_period_size(params, &frames, &dir); handle->frames = frames; return 0; } int audio_play(audio_handle *handle, char *buf) { char t[TEMP_BUF_SZ]; for(int i = 0; ;) { if(i >= REC_CAP) break;; memset(t, 0, TEMP_BUF_SZ); memcpy(t, &(buf[i]), MIN(TEMP_BUF_SZ, REC_CAP - i)); int rc = snd_pcm_writei(HANDLE, t, FRAMES); if (rc == -EPIPE) { err("underrun occurred\n"); snd_pcm_prepare(HANDLE); } else if (rc < 0) { err("error from writei: %s\n", snd_strerror(rc)); } else if (rc != FRAMES) { err("short write, write %d frames\n", rc); } i += TEMP_BUF_SZ; } return 0; } int audio_record(audio_handle *handle, char *buf) { char t[TEMP_BUF_SZ]; for(int i = 0; ;) { if(i >= REC_CAP) break; memset(t, 0, TEMP_BUF_SZ); int rc = snd_pcm_readi(HANDLE, t, FRAMES); if (rc == -EPIPE) { err("overrun occurred\n"); snd_pcm_prepare(HANDLE); } else if (rc < 0) { err("error from read: %s\n", snd_strerror(rc)); } else if (rc != FRAMES) { err("short read, read %d frames\n", rc); } memcpy(&(buf[i]), t, MIN(TEMP_BUF_SZ, REC_CAP - i)); i += TEMP_BUF_SZ; } return 0; } void audio_destroy(audio_handle *handle) { snd_pcm_drain(HANDLE); snd_pcm_close(HANDLE); free(handle->h); }