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);
}
예제 #2
0
void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) {
    int fd = -1;
    AudioDeviceDescription desc;
    am_sample_rates_t      *sr;
    /* hardcoded bits and channels */
    int bits[] = {8, 16}; 
    int bitsCount = 2;
    int channels[] = {1, 2}; 
    int channelsCount = 2;
    /* for querying sample rates */
    int err;
    int ch, b, s;

    TRACE2("DAUDIO_GetFormats, mixer %d, isSource=%d\n", mixerIndex, isSource);
    if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) {
	fd = open(desc.pathctl, O_RDONLY);
    }
    if (fd < 0) {
	ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex);
	return;
    }

    /* get sample rates */
    sr = (am_sample_rates_t*) malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(MAX_SAMPLE_RATES));
    if (sr == NULL) {
	ERROR1("DAUDIO_GetFormats: out of memory for mixer %d\n", (int) mixerIndex);
	close(fd);
	return;
    }
    
    sr->num_samp_rates = MAX_SAMPLE_RATES;
    sr->type = isSource?AUDIO_PLAY:AUDIO_RECORD;
    sr->samp_rates[0] = -2;
    err = ioctl(fd, AUDIO_MIXER_GET_SAMPLE_RATES, sr);
    if (err < 0) {
	ERROR1("  DAUDIO_GetFormats: AUDIO_MIXER_GET_SAMPLE_RATES failed for mixer %d!\n", 
	       (int)mixerIndex);
	ERROR2(" -> num_sample_rates=%d sample_rates[0] = %d\n",
	       (int) sr->num_samp_rates,
	       (int) sr->samp_rates[0]);
	/* Some Solaris 8 drivers fail for get sample rates!
	 * Do as if we support all sample rates
	 */
	sr->flags = MIXER_SR_LIMITS;
    }
    if ((sr->flags & MIXER_SR_LIMITS)
	|| (sr->num_samp_rates > MAX_SAMPLE_RATES)) {
#ifdef USE_TRACE
	if ((sr->flags & MIXER_SR_LIMITS)) {
	    TRACE1("  DAUDIO_GetFormats: floating sample rate allowed by mixer %d\n", 
		   (int)mixerIndex);
	}
	if (sr->num_samp_rates > MAX_SAMPLE_RATES) {
	    TRACE2("  DAUDIO_GetFormats: more than %d formats. Use -1 for sample rates mixer %d\n", 
		   MAX_SAMPLE_RATES, (int)mixerIndex);
	}
#endif
	/*
	 * Fake it to have only one sample rate: -1
	 */
	sr->num_samp_rates = 1;
	sr->samp_rates[0] = -1;
    }
    close(fd);

    for (ch = 0; ch < channelsCount; ch++) {
	for (b = 0; b < bitsCount; b++) {
	    for (s = 0; s < sr->num_samp_rates; s++) {
		DAUDIO_AddAudioFormat(creator, 
				      bits[b], /* significant bits */
				      0, /* frameSize: let it be calculated */
				      channels[ch], 
				      (float) ((int) sr->samp_rates[s]),
				      DAUDIO_PCM, /* encoding - let's only do PCM */
				      (bits[b] > 8)?TRUE:TRUE, /* isSigned */
#if (X_WORD_ORDER == TRUE)
				      FALSE /* little endian */
#else
				      (bits[b] > 8)?TRUE:FALSE  /* big endian */
#endif
				      );
	    }
	}
    }
    free(sr);
}