static HRESULT SetFormat(IDsDriverBufferImpl *This, LPWAVEFORMATEX pwfx) { snd_pcm_t *pcm = NULL; snd_pcm_hw_params_t *hw_params = This->hw_params; unsigned int buffer_time = 500000; snd_pcm_format_t format = -1; snd_pcm_uframes_t psize; DWORD rate = pwfx->nSamplesPerSec; int err=0; switch (pwfx->wBitsPerSample) { case 8: format = SND_PCM_FORMAT_U8; break; case 16: format = SND_PCM_FORMAT_S16_LE; break; case 24: format = SND_PCM_FORMAT_S24_3LE; break; case 32: format = SND_PCM_FORMAT_S32_LE; break; default: FIXME("Unsupported bpp: %d\n", pwfx->wBitsPerSample); return DSERR_GENERIC; } err = snd_pcm_open(&pcm, WOutDev[This->drv->wDevID].pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if (err < 0) { if (errno != EBUSY || !This->pcm) { WARN("Cannot open sound device: %s\n", snd_strerror(err)); return DSERR_GENERIC; } snd_pcm_drop(This->pcm); snd_pcm_close(This->pcm); This->pcm = NULL; err = snd_pcm_open(&pcm, WOutDev[This->drv->wDevID].pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if (err < 0) { WARN("Cannot open sound device: %s\n", snd_strerror(err)); return DSERR_BUFFERLOST; } } /* Set some defaults */ snd_pcm_hw_params_any(pcm, hw_params); err = snd_pcm_hw_params_set_channels(pcm, hw_params, pwfx->nChannels); if (err < 0) { WARN("Could not set channels to %d\n", pwfx->nChannels); goto err; } err = snd_pcm_hw_params_set_format(pcm, hw_params, format); if (err < 0) { WARN("Could not set format to %d bpp\n", pwfx->wBitsPerSample); goto err; } /* Alsa's rate resampling is only used if the application specifically requests * a buffer at a certain frequency, else it is better to disable it due to unwanted * side effects, which may include: Less granular pointer, changing buffer sizes, etc */ #if SND_LIB_VERSION >= 0x010009 snd_pcm_hw_params_set_rate_resample(pcm, hw_params, 0); #endif err = snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, NULL); if (err < 0) { rate = pwfx->nSamplesPerSec; WARN("Could not set rate\n"); goto err; } if (!ALSA_NearMatch(rate, pwfx->nSamplesPerSec)) { WARN("Could not set sound rate to %d, but instead to %d\n", pwfx->nSamplesPerSec, rate); pwfx->nSamplesPerSec = rate; pwfx->nAvgBytesPerSec = rate * pwfx->nBlockAlign; /* Let DirectSound detect this */ } snd_pcm_hw_params_set_periods_integer(pcm, hw_params); snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, NULL); buffer_time = 10000; snd_pcm_hw_params_set_period_time_near(pcm, hw_params, &buffer_time, NULL); err = snd_pcm_hw_params(pcm, hw_params); err = snd_pcm_sw_params(pcm, This->sw_params); snd_pcm_prepare(pcm); err = snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL); TRACE("Period size is: %lu\n", psize); /* ALSA needs at least 3 buffers to work successfully */ This->mmap_commitahead = 3 * psize; while (This->mmap_commitahead <= 512) This->mmap_commitahead += psize; if (This->pcm) { snd_pcm_drop(This->pcm); snd_pcm_close(This->pcm); } This->pcm = pcm; snd_pcm_prepare(This->pcm); DSDB_CreateMMAP(This); return S_OK; err: if (err < 0) WARN("Failed to apply changes: %s\n", snd_strerror(err)); if (!This->pcm) This->pcm = pcm; else snd_pcm_close(pcm); if (This->pcm) snd_pcm_hw_params_current(This->pcm, This->hw_params); return DSERR_BADFORMAT; }
void stop_audio(void) { snd_pcm_drop(playback_handle); }