TErrors SalsaStream::setChannelCount(TChannels channels) { if(pcm_state_ != CLOSED) refreshState(); if(pcm_state_ == OPENED || pcm_state_ == SETUP) { snd_pcm_hw_params_alloca(&hw_config_); snd_pcm_hw_params_current(pcm_, hw_config_); unsigned int ch = channels; int err = snd_pcm_hw_params_set_channels_near(pcm_, hw_config_, &ch); CHECK_SNDERROR(err, E_STREAM_CONFIG); channels_ = (TChannels) ch; if(channels != ch){ stringstream s; const char* dir = (direction_==INPUT_STREAM)?"Input":"Output"; s << dir<< " stream: "<< name_ << "channel number: given = " << channels << "applied = " << ch; LOGGER().warning(E_STREAM_PARAM_DIFFERENCE, s.str().c_str()); return E_STREAM_PARAM_DIFFERENCE; } snd_pcm_hw_params(pcm_, hw_config_); } else channels_ = channels; return E_OK; }
static void alsa_fill_w (snd_pcm_t *pcm_handle) { snd_pcm_hw_params_t *hwparams=NULL; int channels; snd_pcm_uframes_t buffer_size; int buffer_size_bytes; void *buffer; /* Allocate the snd_pcm_hw_params_t structure on the stack. */ snd_pcm_hw_params_alloca(&hwparams); snd_pcm_hw_params_current(pcm_handle, hwparams); /* get channels */ snd_pcm_hw_params_get_channels (hwparams, &channels); /* get buffer size */ snd_pcm_hw_params_get_buffer_size (hwparams, &buffer_size); /* fill half */ buffer_size /= 2; /* allocate buffer assuming 2 bytes per sample */ buffer_size_bytes = buffer_size * channels * 2; buffer = alloca (buffer_size_bytes); memset (buffer, 0, buffer_size_bytes); /* write data */ snd_pcm_writei(pcm_handle, buffer, buffer_size); }
TErrors SalsaStream::setSampleRate(TSampleRate sample_rate) { if(pcm_state_ != CLOSED) refreshState(); if(pcm_state_ == OPENED || pcm_state_ == SETUP) { snd_pcm_hw_params_alloca(&hw_config_); snd_pcm_hw_params_current(pcm_, hw_config_); unsigned int rate = sample_rate; int err=snd_pcm_hw_params_set_rate_near(pcm_, hw_config_, &rate, NULL); CHECK_SNDERROR(err, E_STREAM_CONFIG); rate_ = rate; if(sample_rate != rate) { stringstream s; const char* dir = (direction_==INPUT_STREAM)?"Input":"Output"; s << dir << " stream: "<< name_ << "Sample rate: given = " << sample_rate << "applied = " << rate; LOGGER().warning(E_STREAM_PARAM_DIFFERENCE, s.str().c_str()); return E_STREAM_PARAM_DIFFERENCE; } snd_pcm_hw_params(pcm_, hw_config_); } else rate_ = sample_rate; return E_OK; }
static ALCboolean alsa_start_playback(ALCdevice *device) { alsa_data *data = (alsa_data*)device->ExtraData; snd_pcm_hw_params_t *hp = NULL; snd_pcm_access_t access; const char *funcerr; int err; snd_pcm_hw_params_malloc(&hp); #define CHECK(x) if((funcerr=#x),(err=(x)) < 0) goto error CHECK(snd_pcm_hw_params_current(data->pcmHandle, hp)); /* retrieve configuration info */ CHECK(snd_pcm_hw_params_get_access(hp, &access)); #undef CHECK snd_pcm_hw_params_free(hp); hp = NULL; data->size = snd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateSize); if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { data->buffer = malloc(data->size); if(!data->buffer) { ERR("buffer malloc failed\n"); return ALC_FALSE; } data->thread = StartThread(ALSANoMMapProc, device); } else { err = snd_pcm_prepare(data->pcmHandle); if(err < 0) { ERR("snd_pcm_prepare(data->pcmHandle) failed: %s\n", snd_strerror(err)); return ALC_FALSE; } data->thread = StartThread(ALSAProc, device); } if(data->thread == NULL) { ERR("Could not create playback thread\n"); free(data->buffer); data->buffer = NULL; return ALC_FALSE; } return ALC_TRUE; error: ERR("%s failed: %s\n", funcerr, snd_strerror(err)); if(hp) snd_pcm_hw_params_free(hp); return ALC_FALSE; }
int snd_send(FILE * fp, size_t n) { snd_pcm_format_t format; unsigned int nchannels; snd_pcm_uframes_t period; snd_pcm_hw_params_t *params; snd_pcm_hw_params_alloca(¶ms); snd_pcm_hw_params_current(pcm, params); snd_pcm_hw_params_get_format(params, &format); snd_pcm_hw_params_get_channels(params, &nchannels); snd_pcm_hw_params_get_period_size(params, &period, 0); int framesize = snd_pcm_format_width(format) / 8 * nchannels; unsigned char buf[period * framesize * 128]; size_t l; while (n > sizeof(buf)) { if ((l = fread(buf, 1, sizeof(buf), fp))) { switch (snd_pcm_writei(pcm, buf, l / framesize)) { case -EBADF: return -1; case -EPIPE: #ifndef NDEBUG snd_pcm_recover(pcm, -EPIPE, 0); #else snd_pcm_prepare(pcm); #endif } } else goto EOS; n -= l; } if ((l = fread(buf, 1, n, fp))) snd_pcm_writei(pcm, buf, l / framesize); if (l < n) EOS:if (ftell(fp) > 0) eputs("Unexpected end of stream"); return snd_pcm_drain(pcm); }
int main(int argc, char *argv[]) { const char *dev; int r, cap, count = 0; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_status_t *status; snd_pcm_t *pcm; unsigned rate = 44100; unsigned periods = 2; snd_pcm_uframes_t boundary, buffer_size = 44100/10; /* 100s */ int dir = 1; struct timespec start, last_timestamp = { 0, 0 }; uint64_t start_us, last_us = 0; snd_pcm_sframes_t last_avail = 0, last_delay = 0; struct pollfd *pollfds; int n_pollfd; int64_t sample_count = 0; struct sched_param sp; r = -1; #ifdef _POSIX_PRIORITY_SCHEDULING sp.sched_priority = 5; r = pthread_setschedparam(pthread_self(), SCHED_RR, &sp); #endif if (r) printf("Could not get RT prio. :(\n"); snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); snd_pcm_status_alloca(&status); r = clock_gettime(CLOCK_MONOTONIC, &start); assert(r == 0); start_us = timespec_us(&start); dev = argc > 1 ? argv[1] : "front:AudioPCI"; cap = argc > 2 ? atoi(argv[2]) : 0; if (cap == 0) r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_PLAYBACK, 0); else r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_CAPTURE, 0); assert(r == 0); r = snd_pcm_hw_params_any(pcm, hwparams); assert(r == 0); r = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 0); assert(r == 0); r = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); assert(r == 0); r = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE); assert(r == 0); r = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, NULL); assert(r == 0); r = snd_pcm_hw_params_set_channels(pcm, hwparams, 2); assert(r == 0); r = snd_pcm_hw_params_set_periods_integer(pcm, hwparams); assert(r == 0); r = snd_pcm_hw_params_set_periods_near(pcm, hwparams, &periods, &dir); assert(r == 0); r = snd_pcm_hw_params_set_buffer_size_near(pcm, hwparams, &buffer_size); assert(r == 0); r = snd_pcm_hw_params(pcm, hwparams); assert(r == 0); r = snd_pcm_hw_params_current(pcm, hwparams); assert(r == 0); r = snd_pcm_sw_params_current(pcm, swparams); assert(r == 0); if (cap == 0) r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 1); else r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 0); assert(r == 0); r = snd_pcm_sw_params_set_period_event(pcm, swparams, 0); assert(r == 0); r = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); assert(r == 0); r = snd_pcm_sw_params_set_start_threshold(pcm, swparams, buffer_size); assert(r == 0); r = snd_pcm_sw_params_get_boundary(swparams, &boundary); assert(r == 0); r = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary); assert(r == 0); r = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE); assert(r == 0); r = snd_pcm_sw_params(pcm, swparams); assert(r == 0); r = snd_pcm_prepare(pcm); assert(r == 0); r = snd_pcm_sw_params_current(pcm, swparams); assert(r == 0); /* assert(snd_pcm_hw_params_is_monotonic(hwparams) > 0); */ n_pollfd = snd_pcm_poll_descriptors_count(pcm); assert(n_pollfd > 0); pollfds = malloc(sizeof(struct pollfd) * n_pollfd); assert(pollfds); r = snd_pcm_poll_descriptors(pcm, pollfds, n_pollfd); assert(r == n_pollfd); printf("Starting. Buffer size is %u frames\n", (unsigned int) buffer_size); if (cap) { r = snd_pcm_start(pcm); assert(r == 0); } for (;;) { snd_pcm_sframes_t avail, delay; struct timespec now, timestamp; unsigned short revents; int handled = 0; uint64_t now_us, timestamp_us; snd_pcm_state_t state; unsigned long long pos; r = poll(pollfds, n_pollfd, 0); assert(r >= 0); r = snd_pcm_poll_descriptors_revents(pcm, pollfds, n_pollfd, &revents); assert(r == 0); if (cap == 0) assert((revents & ~POLLOUT) == 0); else assert((revents & ~POLLIN) == 0); avail = snd_pcm_avail(pcm); assert(avail >= 0); r = snd_pcm_status(pcm, status); assert(r == 0); /* This assertion fails from time to time. ALSA seems to be broken */ /* assert(avail == (snd_pcm_sframes_t) snd_pcm_status_get_avail(status)); */ /* printf("%lu %lu\n", (unsigned long) avail, (unsigned long) snd_pcm_status_get_avail(status)); */ snd_pcm_status_get_htstamp(status, ×tamp); delay = snd_pcm_status_get_delay(status); state = snd_pcm_status_get_state(status); r = clock_gettime(CLOCK_MONOTONIC, &now); assert(r == 0); assert(!revents || avail > 0); if ((!cap && avail) || (cap && (unsigned)avail >= buffer_size)) { snd_pcm_sframes_t sframes; static const uint16_t psamples[2] = { 0, 0 }; uint16_t csamples[2]; if (cap == 0) sframes = snd_pcm_writei(pcm, psamples, 1); else sframes = snd_pcm_readi(pcm, csamples, 1); assert(sframes == 1); handled = 1; sample_count++; } if (!handled && memcmp(×tamp, &last_timestamp, sizeof(timestamp)) == 0 && avail == last_avail && delay == last_delay) { /* This is boring */ continue; } now_us = timespec_us(&now); timestamp_us = timespec_us(×tamp); if (cap == 0) pos = (unsigned long long) ((sample_count - handled - delay) * 1000000LU / 44100); else pos = (unsigned long long) ((sample_count - handled + delay) * 1000000LU / 44100); if (count++ % 50 == 0) printf("Elapsed\tCPU\tALSA\tPos\tSamples\tavail\tdelay\trevents\thandled\tstate\n"); printf("%llu\t%llu\t%llu\t%llu\t%llu\t%li\t%li\t%i\t%i\t%i\n", (unsigned long long) (now_us - last_us), (unsigned long long) (now_us - start_us), (unsigned long long) (timestamp_us ? timestamp_us - start_us : 0), pos, (unsigned long long) sample_count, (signed long) avail, (signed long) delay, revents, handled, state); if (cap == 0) /** When this assert is hit, most likely something bad * happened, i.e. the avail jumped suddenly. */ assert((unsigned) avail <= buffer_size); last_avail = avail; last_delay = delay; last_timestamp = timestamp; last_us = now_us; } return 0; }
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_get_period_size(hw_params, &psize, NULL); buffer_time = 16; snd_pcm_hw_params_set_periods_near(pcm, hw_params, &buffer_time, NULL); if (!This->mmap) { HeapFree(GetProcessHeap(), 0, This->mmap_buffer); This->mmap_buffer = NULL; } err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED); if (err >= 0) This->mmap = 1; else { This->mmap = 0; err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); } err = snd_pcm_hw_params(pcm, hw_params); /* 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; }
static int alsa_audio_reconfig(audio_decoder_t *ad) { decoder_t *d = (decoder_t *)ad; snd_pcm_t *h; int r; alsa_audio_fini(ad); if(d->h != NULL) { snd_pcm_close(d->h); d->h = NULL; TRACE(TRACE_DEBUG, "ALSA", "Closing device"); } const char *dev = alsa_get_devicename(); if((r = snd_pcm_open(&h, dev, SND_PCM_STREAM_PLAYBACK, 0) < 0)) { TRACE(TRACE_ERROR, "ALSA", "Unable to open %s -- %s", dev, snd_strerror(r)); return -1; } r = snd_pcm_set_params(h, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, 2, 48000, 0, 100000); if(r < 0) { TRACE(TRACE_ERROR, "ALSA", "Unable to set params on %s -- %s", dev, snd_strerror(r)); return -1; } snd_pcm_hw_params_t *hwp; snd_pcm_hw_params_alloca(&hwp); snd_pcm_hw_params_current(h, hwp); unsigned int val; snd_pcm_uframes_t psize, bsize; snd_pcm_hw_params_get_rate(hwp, &val, 0); ad->ad_out_sample_rate = val; snd_pcm_hw_params_get_period_size(hwp, &psize, 0); ad->ad_tile_size = psize * 2; snd_pcm_hw_params_get_buffer_size(hwp, &bsize); d->max_frames_per_write = bsize; TRACE(TRACE_DEBUG, "ALSA", "Opened %s", dev); ad->ad_out_sample_format = AV_SAMPLE_FMT_S16; ad->ad_out_sample_rate = 48000; ad->ad_out_channel_layout = AV_CH_LAYOUT_STEREO; d->h = h; snd_pcm_prepare(d->h); int channels = 2; d->tmp = malloc(sizeof(uint16_t) * channels * d->max_frames_per_write); return 0; }
int sa_stream_open(sa_stream_t *s) { snd_output_t* out; char* buf; size_t bufsz; snd_pcm_hw_params_t* hwparams; snd_pcm_sw_params_t* swparams; int dir; snd_pcm_uframes_t period; if (s == NULL) { return SA_ERROR_NO_INIT; } if (s->output_unit != NULL) { return SA_ERROR_INVALID; } pthread_mutex_lock(&sa_alsa_mutex); /* Turn off debug output to stderr */ snd_lib_error_set_handler(quiet_error_handler); if (snd_pcm_open(&s->output_unit, "default", SND_PCM_STREAM_PLAYBACK, 0) < 0) { pthread_mutex_unlock(&sa_alsa_mutex); return SA_ERROR_NO_DEVICE; } if (snd_pcm_set_params(s->output_unit, #ifdef SA_LITTLE_ENDIAN SND_PCM_FORMAT_S16_LE, #else SND_PCM_FORMAT_S16_BE, #endif SND_PCM_ACCESS_RW_INTERLEAVED, s->n_channels, s->rate, 1, 500000) < 0) { snd_pcm_close(s->output_unit); s->output_unit = NULL; pthread_mutex_unlock(&sa_alsa_mutex); return SA_ERROR_NOT_SUPPORTED; } /* ugly alsa-pulse plugin detection */ snd_output_buffer_open(&out); snd_pcm_dump(s->output_unit, out); bufsz = snd_output_buffer_string(out, &buf); s->pulseaudio = bufsz >= strlen(ALSA_PA_PLUGIN) && strncmp(buf, ALSA_PA_PLUGIN, strlen(ALSA_PA_PLUGIN)) == 0; snd_output_close(out); snd_pcm_hw_params_alloca(&hwparams); snd_pcm_hw_params_current(s->output_unit, hwparams); snd_pcm_hw_params_get_period_size(hwparams, &period, &dir); pthread_mutex_unlock(&sa_alsa_mutex); return SA_SUCCESS; }
int VPOutPluginAlsa::init(VPlayer *v, VPBuffer *in) { DBG("Alsa:init"); owner = v; bin = in; if (snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NO_AUTO_RESAMPLE) < 0){ DBG("Alsa:init: failed to open pcm"); exit(0); return -1; } snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_malloc(&swparams); snd_pcm_sw_params_current (handle, swparams); snd_pcm_sw_params_set_start_threshold (handle, swparams, VPBUFFER_FRAMES - PERIOD_SIZE); snd_pcm_sw_params (handle, swparams); snd_pcm_sw_params_free(swparams); snd_pcm_hw_params_alloca(¶ms); snd_pcm_hw_params_any(handle, params); snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_format_mask_t *mask; snd_pcm_format_mask_alloca(&mask); snd_pcm_hw_params_get_format_mask(params, mask); if (snd_pcm_format_mask_test(mask, SND_PCM_FORMAT_S32)) { DBG("bit depth is 32"); snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S32); multiplier = (1<<31) -1 ; DBG(multiplier); } else if (snd_pcm_format_mask_test(mask, SND_PCM_FORMAT_S24)) { DBG("bit depth is 24"); snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S24); multiplier = (1<<23) -1; } else if (snd_pcm_format_mask_test(mask, SND_PCM_FORMAT_S16)) { DBG("bit depth is 16"); snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16); multiplier = (1<<15) -1; } else if (snd_pcm_format_mask_test(mask, SND_PCM_FORMAT_S8)) { DBG("bit depth is 8"); snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S8); multiplier = (1<<7) -1;; } snd_pcm_hw_params_set_channels(handle, params, bin->chans); snd_pcm_hw_params_set_period_size(handle, params, PERIOD_SIZE, 0); if (snd_pcm_hw_params(handle, params) < 0) { DBG("Alsa:init: failed to set pcm params"); return -1; } snd_pcm_hw_params_current(handle, params); int dir; snd_pcm_hw_params_get_rate(params, &out_srate, &dir); in_srate = bin->srate; int rerr; rs = src_new(SRC_SINC_FASTEST, bin->chans, &rerr); if (!rs){ DBG("SRC error"<<rerr); return -1; } rd.src_ratio = (out_srate*1.0)/(in_srate*1.0); out_frames = (VPBUFFER_FRAMES*rd.src_ratio)*2; out_buf = (float *)ALIGNED_ALLOC(sizeof(float)*out_frames*bin->chans); out_buf_i = (int *)ALIGNED_ALLOC(sizeof(int)*out_frames*bin->chans); DBG("target rate "<<out_srate); work = true; paused = false; pause_check = false; FULL_MEMORY_BARRIER; in_fd = inotify_init(); if ( in_fd < 0 ) { DBG("error initializing inotify, auto pause won't work"); } else { in_wd[0]=inotify_add_watch( in_fd, "/dev/snd/pcmC0D0p", IN_OPEN | IN_CLOSE ); } fcntl(in_fd, F_SETFL, O_NONBLOCK); worker = new std::thread((void(*)(void*))worker_run, this); worker->high_priority(); DBG("alsa thread made"); DBG((void *)VPOutPluginAlsa::check_contention); VPEvents::getSingleton()->schedulerAddJob((VPEvents::VPJob) VPOutPluginAlsa::check_contention, this,0); return 0; }
static HRESULT WINAPI IDsCaptureDriverBufferImpl_SetFormat(PIDSCDRIVERBUFFER iface, LPWAVEFORMATEX pwfx) { IDsCaptureDriverBufferImpl *This = (IDsCaptureDriverBufferImpl *)iface; WINE_WAVEDEV *wwi = &WInDev[This->drv->wDevID]; snd_pcm_t *pcm = NULL; snd_pcm_hw_params_t *hw_params = This->hw_params; snd_pcm_format_t format = -1; snd_pcm_uframes_t buffer_size; DWORD rate = pwfx->nSamplesPerSec; int err=0; BOOL mmap; TRACE("(%p, %p)\n", iface, pwfx); 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; } /* **** */ EnterCriticalSection(&This->pcm_crst); err = snd_pcm_open(&pcm, wwi->pcmname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); if (err < 0) { if (errno != EBUSY || !This->pcm) { /* **** */ LeaveCriticalSection(&This->pcm_crst); 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, wwi->pcmname, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); if (err < 0) { /* **** */ LeaveCriticalSection(&This->pcm_crst); 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; } 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); buffer_size = This->mmap_buflen_bytes / pwfx->nBlockAlign; snd_pcm_hw_params_set_buffer_size_near(pcm, hw_params, &buffer_size); buffer_size = 5000; snd_pcm_hw_params_set_period_time_near(pcm, hw_params, (unsigned int*)&buffer_size, NULL); err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED); if (err < 0) { err = snd_pcm_hw_params_set_access (pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { WARN("Could not set access\n"); goto err; } mmap = 0; } else mmap = 1; err = snd_pcm_hw_params(pcm, hw_params); if (err < 0) { WARN("Could not set hw parameters\n"); goto err; } if (This->pcm) { snd_pcm_drop(This->pcm); snd_pcm_close(This->pcm); } This->pcm = pcm; This->mmap = mmap; snd_pcm_prepare(This->pcm); CreateMMAP(This); /* **** */ LeaveCriticalSection(&This->pcm_crst); 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); /* **** */ LeaveCriticalSection(&This->pcm_crst); return DSERR_BADFORMAT; }
PyObject* play_os(Py_buffer buffer_obj, int len_samples, int num_channels, int bytes_per_chan, int sample_rate, play_item_t* play_list_head, int latency_us) { char err_msg_buf[SA_ERR_STR_LEN]; audio_blob_t* audio_blob; int bytes_per_frame = bytes_per_chan * num_channels; static char *device = "default"; snd_pcm_format_t sample_format; pthread_t play_thread; int result; snd_pcm_hw_params_t* hw_params; snd_pcm_uframes_t buffer_frames; /* not sure where the best place to do this is or if it matters */ snd_pcm_hw_params_alloca(&hw_params); DBG_PLAY_OS_CALL /* set that format appropriately */ if (bytes_per_chan == 1) { } else if (bytes_per_chan == 2) { sample_format = SND_PCM_FORMAT_S16_LE; } else { ALSA_EXCEPTION("Unsupported Sample Format.", 0, "", err_msg_buf); return NULL; } /* audio blob initial allocation and audio buffer copy */ audio_blob = create_audio_blob(); audio_blob->buffer_obj = buffer_obj; audio_blob->list_mutex = play_list_head->mutex; audio_blob->len_bytes = len_samples * bytes_per_frame; audio_blob->frame_size = bytes_per_frame; /* setup the linked list item for this playback buffer */ grab_mutex(play_list_head->mutex); audio_blob->play_list_item = new_list_item(play_list_head); release_mutex(play_list_head->mutex); /* open access to a PCM device (blocking mode) */ result = snd_pcm_open((snd_pcm_t**)&audio_blob->handle, device, SND_PCM_STREAM_PLAYBACK, 0); if (result < 0) { ALSA_EXCEPTION("Error opening PCM device.", result, snd_strerror(result), err_msg_buf); destroy_audio_blob(audio_blob); return NULL; } /* set the PCM params using ALSA's convenience function */ result = snd_pcm_set_params(audio_blob->handle, sample_format, SND_PCM_ACCESS_RW_INTERLEAVED, num_channels, sample_rate, RESAMPLE, latency_us); if (result < 0) { ALSA_EXCEPTION("Error setting parameters.", result, snd_strerror(result), err_msg_buf); snd_pcm_close(audio_blob->handle); destroy_audio_blob(audio_blob); return NULL; } /* get the HW params (needed for buffer size) */ result = snd_pcm_hw_params_current(audio_blob->handle, hw_params); if (result < 0) { ALSA_EXCEPTION("Error getting hardware parameters.", result, snd_strerror(result), err_msg_buf); snd_pcm_close(audio_blob->handle); destroy_audio_blob(audio_blob); return NULL; } /* get the buffer size */ result = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_frames); if (result < 0) { ALSA_EXCEPTION("Error getting buffer_size.", result, snd_strerror(result), err_msg_buf); snd_pcm_close(audio_blob->handle); destroy_audio_blob(audio_blob); return NULL; } audio_blob->buffer_size = buffer_frames * bytes_per_chan * num_channels; dbg1("ALSA says buffer size is %d bytes\n", audio_blob->buffer_size); /* fire off the playback thread */ result = pthread_create(&play_thread, NULL, playback_thread, (void*)audio_blob); if (result != 0) { ALSA_EXCEPTION("Could not create playback thread.", result, "", err_msg_buf); snd_pcm_close(audio_blob->handle); destroy_audio_blob(audio_blob); return NULL; } return PyLong_FromUnsignedLongLong(audio_blob->play_list_item->play_id); }