static GstCaps * gst_alsa_detect_formats (GstObject * obj, snd_pcm_hw_params_t * hw_params, GstCaps * in_caps) { snd_pcm_format_mask_t *mask; GstStructure *s; GstCaps *caps; gint i; snd_pcm_format_mask_malloc (&mask); snd_pcm_hw_params_get_format_mask (hw_params, mask); caps = gst_caps_new_empty (); for (i = 0; i < gst_caps_get_size (in_caps); ++i) { GstStructure *scopy; gint w, width = 0, depth = 0; s = gst_caps_get_structure (in_caps, i); if (!gst_structure_has_name (s, "audio/x-raw-int")) { GST_DEBUG_OBJECT (obj, "skipping non-int format"); continue; } if (!gst_structure_get_int (s, "width", &width) || !gst_structure_get_int (s, "depth", &depth)) continue; if (width == 0 || (width % 8) != 0) continue; /* Only full byte widths are valid */ for (w = 0; w < G_N_ELEMENTS (pcmformats); w++) if (pcmformats[w].width == width && pcmformats[w].depth == depth) break; if (w == G_N_ELEMENTS (pcmformats)) continue; /* Unknown format */ if (snd_pcm_format_mask_test (mask, pcmformats[w].sformat) && snd_pcm_format_mask_test (mask, pcmformats[w].uformat)) { /* template contains { true, false } or just one, leave it as it is */ scopy = gst_structure_copy (s); } else if (snd_pcm_format_mask_test (mask, pcmformats[w].sformat)) { scopy = gst_structure_copy (s); gst_structure_set (scopy, "signed", G_TYPE_BOOLEAN, TRUE, NULL); } else if (snd_pcm_format_mask_test (mask, pcmformats[w].uformat)) { scopy = gst_structure_copy (s); gst_structure_set (scopy, "signed", G_TYPE_BOOLEAN, FALSE, NULL); } else { scopy = NULL; } if (scopy) { if (width > 8) { /* TODO: proper endianness detection, for now it's CPU endianness only */ gst_structure_set (scopy, "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL); } gst_caps_append_structure (caps, scopy); } } snd_pcm_format_mask_free (mask); gst_caps_unref (in_caps); return caps; }
static int setup(sox_format_t * ft) { priv_t * p = (priv_t *)ft->priv; snd_pcm_hw_params_t * params = NULL; snd_pcm_format_mask_t * mask = NULL; snd_pcm_uframes_t min, max; unsigned n; int err; _(snd_pcm_open, (&p->pcm, ft->filename, ft->mode == 'r'? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0)); _(snd_pcm_hw_params_malloc, (¶ms)); _(snd_pcm_hw_params_any, (p->pcm, params)); #if SND_LIB_VERSION >= 0x010009 /* Disable alsa-lib resampling: */ _(snd_pcm_hw_params_set_rate_resample, (p->pcm, params, 0)); #endif _(snd_pcm_hw_params_set_access, (p->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED)); _(snd_pcm_format_mask_malloc, (&mask)); /* Set format: */ snd_pcm_hw_params_get_format_mask(params, mask); _(select_format, (&ft->encoding.encoding, &ft->encoding.bits_per_sample, mask, &p->format)); _(snd_pcm_hw_params_set_format, (p->pcm, params, p->format)); snd_pcm_format_mask_free(mask), mask = NULL; n = ft->signal.rate; /* Set rate: */ _(snd_pcm_hw_params_set_rate_near, (p->pcm, params, &n, 0)); ft->signal.rate = n; n = ft->signal.channels; /* Set channels: */ _(snd_pcm_hw_params_set_channels_near, (p->pcm, params, &n)); ft->signal.channels = n; /* Set buf_len > > sox_globals.bufsiz for no underrun: */ p->buf_len = sox_globals.bufsiz * 8 / NBYTES / ft->signal.channels; _(snd_pcm_hw_params_get_buffer_size_min, (params, &min)); _(snd_pcm_hw_params_get_buffer_size_max, (params, &max)); p->period = range_limit(p->buf_len, min, max) / 8; p->buf_len = p->period * 8; _(snd_pcm_hw_params_set_period_size_near, (p->pcm, params, &p->period, 0)); _(snd_pcm_hw_params_set_buffer_size_near, (p->pcm, params, &p->buf_len)); if (p->period * 2 > p->buf_len) { lsx_fail_errno(ft, SOX_EPERM, "buffer too small"); goto error; } _(snd_pcm_hw_params, (p->pcm, params)); /* Configure ALSA */ snd_pcm_hw_params_free(params), params = NULL; _(snd_pcm_prepare, (p->pcm)); p->buf_len *= ft->signal.channels; /* No longer in `frames' */ p->buf = lsx_malloc(p->buf_len * NBYTES); return SOX_SUCCESS; error: if (mask) snd_pcm_format_mask_free(mask); if (params) snd_pcm_hw_params_free(params); return SOX_EOF; }
static void as_setup_format_combo(GawSndData *snd) { GtkWidget *combo = snd->w_format; snd_pcm_format_t format = snd->sparams->format; snd_pcm_t *pcm; snd_pcm_hw_params_t *hwparams; snd_pcm_format_mask_t *formatMask; AsFormatList *p; int i ; int err; for ( i = snd->n_format ; i > 0; i-- ){ gtk_combo_box_text_remove (GTK_COMBO_BOX_TEXT (combo), i - 1 ); } snd->n_format = 0; snd_pcm_hw_params_alloca(&hwparams); snd_pcm_format_mask_alloca(&formatMask); err = snd_pcm_open(&pcm, snd->sparams->device_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); if ( err < 0 ) { return; } err = snd_pcm_hw_params_any(pcm, hwparams); if ( err < 0 ) { snd_pcm_close(pcm); return; } snd_pcm_hw_params_get_format_mask(hwparams, formatMask); for( p = as_format_list, i = 0 ; p->name ; p++, i++ ){ if ( snd_pcm_format_mask_test ( formatMask, p->format ) < 0 ){ continue; } gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), p->name ); // msg_dbg("as_format %d '%s'", snd->n_format, p->name ); snd->n_format++; if ( p->format == format ) { gtk_combo_box_set_active (GTK_COMBO_BOX (combo), i); } } snd_pcm_close(pcm); }
void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { snd_pcm_t* handle; snd_pcm_format_mask_t* formatMask; snd_pcm_format_t format; snd_pcm_hw_params_t* hwParams; int handledBits[MAX_BIT_INDEX+1]; int ret; int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc; int origSampleSizeInBytes, origSignificantBits; int channels, minChannels, maxChannels; int rate, bitIndex; for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE; if (openPCMfromDeviceID(deviceID, &handle, isSource, TRUE /*query hardware*/) < 0) { return; } ret = snd_pcm_format_mask_malloc(&formatMask); if (ret != 0) { ERROR1("snd_pcm_format_mask_malloc returned error %d\n", ret); } else { ret = snd_pcm_hw_params_malloc(&hwParams); if (ret != 0) { ERROR1("snd_pcm_hw_params_malloc returned error %d\n", ret); } else { ret = snd_pcm_hw_params_any(handle, hwParams); if (ret != 0) { ERROR1("snd_pcm_hw_params_any returned error %d\n", ret); } } snd_pcm_hw_params_get_format_mask(hwParams, formatMask); #ifdef ALSA_PCM_NEW_HW_PARAMS_API if (ret == 0) { ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels); if (ret != 0) { ERROR1("snd_pcm_hw_params_get_channels_min returned error %d\n", ret); } } if (ret == 0) { ret = snd_pcm_hw_params_get_channels_max(hwParams, &maxChannels); if (ret != 0) { ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret); } } #else minChannels = snd_pcm_hw_params_get_channels_min(hwParams); maxChannels = snd_pcm_hw_params_get_channels_max(hwParams); if (minChannels > maxChannels) { ERROR2("MinChannels=%d, maxChannels=%d\n", minChannels, maxChannels); } #endif // since we queried the hw: device, for many soundcards, it will only // report the maximum number of channels (which is the only way to talk // to the hw: device). Since we will, however, open the plughw: device // when opening the Source/TargetDataLine, we can safely assume that // also the channels 1..maxChannels are available. #ifdef ALSA_PCM_USE_PLUGHW minChannels = 1; #endif if (ret == 0) { // plughw: supports any sample rate rate = -1; for (format = 0; format <= SND_PCM_FORMAT_LAST; format++) { if (snd_pcm_format_mask_test(formatMask, format)) { // format exists if (getFormatFromAlsaFormat(format, &origSampleSizeInBytes, &origSignificantBits, &isSigned, &isBigEndian, &enc)) { // now if we use plughw:, we can use any bit size below the // natively supported ones. Some ALSA drivers only support the maximum // bit size, so we add any sample rates below the reported one. // E.g. this iteration reports support for 16-bit. // getBitIndex will return 2, so it will add entries for // 16-bit (bitIndex=2) and in the next do-while loop iteration, // it will decrease bitIndex and will therefore add 8-bit support. bitIndex = getBitIndex(origSampleSizeInBytes, origSignificantBits); do { if (bitIndex == 0 || bitIndex == MAX_BIT_INDEX || !handledBits[bitIndex]) { handledBits[bitIndex] = TRUE; sampleSizeInBytes = getSampleSizeInBytes(bitIndex, origSampleSizeInBytes); significantBits = getSignificantBits(bitIndex, origSignificantBits); if (maxChannels - minChannels > MAXIMUM_LISTED_CHANNELS) { // avoid too many channels explicitly listed // just add -1, min, and max DAUDIO_AddAudioFormat(creator, significantBits, -1, -1, rate, enc, isSigned, isBigEndian); DAUDIO_AddAudioFormat(creator, significantBits, sampleSizeInBytes * minChannels, minChannels, rate, enc, isSigned, isBigEndian); DAUDIO_AddAudioFormat(creator, significantBits, sampleSizeInBytes * maxChannels, maxChannels, rate, enc, isSigned, isBigEndian); } else { for (channels = minChannels; channels <= maxChannels; channels++) { DAUDIO_AddAudioFormat(creator, significantBits, (channels < 0)?-1:(sampleSizeInBytes * channels), channels, rate, enc, isSigned, isBigEndian); } } } #ifndef ALSA_PCM_USE_PLUGHW // without plugin, do not add fake formats break; #endif } while (--bitIndex > 0); } else { TRACE1("could not get format from alsa for format %d\n", format); } } else { //TRACE1("Format %d not supported\n", format); } } // for loop snd_pcm_hw_params_free(hwParams); } snd_pcm_format_mask_free(formatMask); } snd_pcm_close(handle); }
/* Fill caps with the device capabilities. Return 0 on error. */ static int fill_capabilities (struct output_driver_caps *caps) { snd_pcm_hw_params_t *hw_params; snd_pcm_format_mask_t *format_mask; int err; unsigned val; if ((err = snd_pcm_open(&handle, options_get_str("AlsaDevice"), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { error ("Can't open audio: %s", snd_strerror(err)); return 0; } if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) { error ("Can't allocate alsa hardware parameters structure: %s", snd_strerror(err)); snd_pcm_close (handle); return 0; } if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) { error ("Can't initialize hardware parameters structure: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); snd_pcm_close (handle); return 0; } if ((err = snd_pcm_hw_params_get_channels_min (hw_params, &val)) < 0) { error ("Can't get the minimum number of channels: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); snd_pcm_close (handle); return 0; } caps->min_channels = val; if ((err = snd_pcm_hw_params_get_channels_max (hw_params, &val)) < 0) { error ("Can't get the maximum number of channels: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); snd_pcm_close (handle); return 0; } caps->max_channels = val; if ((err = snd_pcm_format_mask_malloc(&format_mask)) < 0) { error ("Can't allocate format mask: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); snd_pcm_close (handle); return 0; } snd_pcm_hw_params_get_format_mask (hw_params, format_mask); caps->formats = SFMT_NE; if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_S8)) caps->formats |= SFMT_S8; if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_U8)) caps->formats |= SFMT_U8; if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_S16)) caps->formats |= SFMT_S16; if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_U16)) caps->formats |= SFMT_U16; #if 0 if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_S24)) caps->formats |= SFMT_S32; /* conversion needed */ #endif if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_S32)) caps->formats |= SFMT_S32; if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_U32)) caps->formats |= SFMT_U32; snd_pcm_format_mask_free (format_mask); snd_pcm_hw_params_free (hw_params); snd_pcm_close (handle); handle = NULL; return 1; }
/************************************************************************** * ALSA_TraceParameters [internal] * * used to trace format changes, hw and sw parameters */ void ALSA_TraceParameters(snd_pcm_hw_params_t * hw_params, snd_pcm_sw_params_t * sw, int full) { int err; snd_pcm_format_t format; snd_pcm_access_t access; #define X(x) ((x)? "true" : "false") if (full) TRACE("FLAGS: sampleres=%s overrng=%s pause=%s resume=%s syncstart=%s batch=%s block=%s double=%s " "halfd=%s joint=%s\n", X(snd_pcm_hw_params_can_mmap_sample_resolution(hw_params)), X(snd_pcm_hw_params_can_overrange(hw_params)), X(snd_pcm_hw_params_can_pause(hw_params)), X(snd_pcm_hw_params_can_resume(hw_params)), X(snd_pcm_hw_params_can_sync_start(hw_params)), X(snd_pcm_hw_params_is_batch(hw_params)), X(snd_pcm_hw_params_is_block_transfer(hw_params)), X(snd_pcm_hw_params_is_double(hw_params)), X(snd_pcm_hw_params_is_half_duplex(hw_params)), X(snd_pcm_hw_params_is_joint_duplex(hw_params))); #undef X err = snd_pcm_hw_params_get_access(hw_params, &access); if (err >= 0) { TRACE("access=%s\n", snd_pcm_access_name(access)); } else { snd_pcm_access_mask_t * acmask; acmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_access_mask_sizeof()); snd_pcm_hw_params_get_access_mask(hw_params, acmask); for ( access = SND_PCM_ACCESS_MMAP_INTERLEAVED; access <= SND_PCM_ACCESS_LAST; access++) if (snd_pcm_access_mask_test(acmask, access)) TRACE("access=%s\n", snd_pcm_access_name(access)); HeapFree( GetProcessHeap(), 0, acmask ); } err = snd_pcm_hw_params_get_format(hw_params, &format); if (err >= 0) { TRACE("format=%s\n", snd_pcm_format_name(format)); } else { snd_pcm_format_mask_t * fmask; fmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof()); snd_pcm_hw_params_get_format_mask(hw_params, fmask); for ( format = SND_PCM_FORMAT_S8; format <= SND_PCM_FORMAT_LAST ; format++) if ( snd_pcm_format_mask_test(fmask, format) ) TRACE("format=%s\n", snd_pcm_format_name(format)); HeapFree( GetProcessHeap(), 0, fmask ); } do { int err=0; unsigned int val=0; err = snd_pcm_hw_params_get_channels(hw_params, &val); if (err<0) { unsigned int min = 0; unsigned int max = 0; err = snd_pcm_hw_params_get_channels_min(hw_params, &min), err = snd_pcm_hw_params_get_channels_max(hw_params, &max); TRACE("channels_min=%u, channels_min_max=%u\n", min, max); } else { TRACE("channels=%d\n", val); } } while(0); do { int err=0; snd_pcm_uframes_t val=0; err = snd_pcm_hw_params_get_buffer_size(hw_params, &val); if (err<0) { snd_pcm_uframes_t min = 0; snd_pcm_uframes_t max = 0; err = snd_pcm_hw_params_get_buffer_size_min(hw_params, &min), err = snd_pcm_hw_params_get_buffer_size_max(hw_params, &max); TRACE("buffer_size_min=%lu, buffer_size_min_max=%lu\n", min, max); } else { TRACE("buffer_size=%lu\n", val); } } while(0); #define X(x) do { \ int err=0; \ int dir=0; \ unsigned int val=0; \ err = snd_pcm_hw_params_get_##x(hw_params,&val, &dir); \ if (err<0) { \ unsigned int min = 0; \ unsigned int max = 0; \ err = snd_pcm_hw_params_get_##x##_min(hw_params, &min, &dir); \ err = snd_pcm_hw_params_get_##x##_max(hw_params, &max, &dir); \ TRACE(#x "_min=%u " #x "_max=%u\n", min, max); \ } else \ TRACE(#x "=%d\n", val); \ } while(0) X(rate); X(buffer_time); X(periods); do { int err=0; int dir=0; snd_pcm_uframes_t val=0; err = snd_pcm_hw_params_get_period_size(hw_params, &val, &dir); if (err<0) { snd_pcm_uframes_t min = 0; snd_pcm_uframes_t max = 0; err = snd_pcm_hw_params_get_period_size_min(hw_params, &min, &dir), err = snd_pcm_hw_params_get_period_size_max(hw_params, &max, &dir); TRACE("period_size_min=%lu, period_size_min_max=%lu\n", min, max); } else { TRACE("period_size=%lu\n", val); } } while(0); X(period_time); #undef X if (!sw) return; }
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; }
/*---------------------------------------------------------------------------- ** ALSA_ComputeCaps ** ** Given an ALSA PCM, figure out our HW CAPS structure info. ** ctl can be null, pcm is required, as is all output parms. ** */ static int ALSA_ComputeCaps(snd_ctl_t *ctl, snd_pcm_t *pcm, WORD *channels, DWORD *flags, DWORD *formats, DWORD *supports) { snd_pcm_hw_params_t *hw_params; snd_pcm_format_mask_t *fmask; snd_pcm_access_mask_t *acmask; unsigned int ratemin = 0; unsigned int ratemax = 0; unsigned int chmin = 0; unsigned int chmax = 0; int rc, dir = 0; hw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof() ); fmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof() ); acmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_access_mask_sizeof() ); if ((rc = snd_pcm_hw_params_any(pcm, hw_params)) < 0) goto done; snd_pcm_hw_params_get_format_mask(hw_params, fmask); if ((rc = snd_pcm_hw_params_get_access_mask(hw_params, acmask)) < 0) goto done; if ((rc = snd_pcm_hw_params_get_rate_min(hw_params, &ratemin, &dir)) < 0) goto done; if ((rc = snd_pcm_hw_params_get_rate_max(hw_params, &ratemax, &dir)) < 0) goto done; if ((rc = snd_pcm_hw_params_get_channels_min(hw_params, &chmin)) < 0) goto done; if ((rc = snd_pcm_hw_params_get_channels_max(hw_params, &chmax)) < 0) goto done; #define X(r,v) \ if ( (r) >= ratemin && ( (r) <= ratemax || ratemax == -1) ) \ { \ if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_U8)) \ { \ if (chmin <= 1 && 1 <= chmax) \ *formats |= WAVE_FORMAT_##v##M08; \ if (chmin <= 2 && 2 <= chmax) \ *formats |= WAVE_FORMAT_##v##S08; \ } \ if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_S16_LE)) \ { \ if (chmin <= 1 && 1 <= chmax) \ *formats |= WAVE_FORMAT_##v##M16; \ if (chmin <= 2 && 2 <= chmax) \ *formats |= WAVE_FORMAT_##v##S16; \ } \ } X(11025,1); X(22050,2); X(44100,4); X(48000,48); X(96000,96); #undef X if (chmin > 1) FIXME("Device has a minimum of %d channels\n", chmin); *channels = chmax; /* FIXME: is sample accurate always true ? ** Can we do WAVECAPS_PITCH, WAVECAPS_SYNC, or WAVECAPS_PLAYBACKRATE? */ *supports |= WAVECAPS_SAMPLEACCURATE; *supports |= WAVECAPS_DIRECTSOUND; /* check for volume control support */ if (ctl) { if (snd_ctl_name(ctl)) { snd_hctl_t *hctl; if (snd_hctl_open(&hctl, snd_ctl_name(ctl), 0) >= 0) { snd_hctl_load(hctl); if (!ALSA_CheckSetVolume( hctl, NULL, NULL, NULL, NULL, NULL, NULL, NULL )) { *supports |= WAVECAPS_VOLUME; if (chmin <= 2 && 2 <= chmax) *supports |= WAVECAPS_LRVOLUME; } snd_hctl_free(hctl); snd_hctl_close(hctl); } } } *flags = DSCAPS_CERTIFIED | DSCAPS_CONTINUOUSRATE; *flags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO; *flags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT; if (*formats & (WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_48M08 | WAVE_FORMAT_96M08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_4M16 | WAVE_FORMAT_48M16 | WAVE_FORMAT_96M16) ) *flags |= DSCAPS_PRIMARYMONO; if (*formats & (WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4S16 | WAVE_FORMAT_48S16 | WAVE_FORMAT_96S16) ) *flags |= DSCAPS_PRIMARYSTEREO; if (*formats & (WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_48M08 | WAVE_FORMAT_96M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_96S08) ) *flags |= DSCAPS_PRIMARY8BIT; if (*formats & (WAVE_FORMAT_1M16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_4M16 | WAVE_FORMAT_48M16 | WAVE_FORMAT_96M16 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4S16 | WAVE_FORMAT_48S16 | WAVE_FORMAT_96S16) ) *flags |= DSCAPS_PRIMARY16BIT; rc = 0; done: if (rc < 0) ERR("failed: %s(%d)\n", snd_strerror(rc), rc); HeapFree( GetProcessHeap(), 0, hw_params ); HeapFree( GetProcessHeap(), 0, fmask ); HeapFree( GetProcessHeap(), 0, acmask ); return rc; }