Ejemplo n.º 1
0
/* alsa_init:
 *  ALSA init routine.
 */
static int alsa_init(int input, int voices)
{
   int ret = 0;
   char tmp1[128], tmp2[128];
   int format = 0;
   unsigned int numfrags = 0;
   snd_pcm_uframes_t fragsize;

   if (input) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Input is not supported"));
      return -1;
   }

   ALSA9_CHECK(snd_output_stdio_attach(&snd_output, stdout, 0));

   alsa_device = get_config_string(uconvert_ascii("sound", tmp1),
				   uconvert_ascii("alsa_device", tmp2),
				   alsa_device);

   alsa_mixer_device = get_config_string(uconvert_ascii("sound", tmp1),
				   uconvert_ascii("alsa_mixer_device", tmp2),
				   alsa_mixer_device);

   fragsize = get_config_int(uconvert_ascii("sound", tmp1),
			     uconvert_ascii("alsa_fragsize", tmp2), 0);

   numfrags = get_config_int(uconvert_ascii("sound", tmp1),
			     uconvert_ascii("alsa_numfrags", tmp2),
			     ALSA_DEFAULT_NUMFRAGS);

   ret = snd_pcm_open(&pcm_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
   if (ret < 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not open card/pcm device"));
      return -1;
   }

   snd_mixer_open(&alsa_mixer, 0);

   if (alsa_mixer
       && snd_mixer_attach(alsa_mixer, alsa_mixer_device) >= 0
       && snd_mixer_selem_register (alsa_mixer, NULL, NULL) >= 0
       && snd_mixer_load(alsa_mixer) >= 0) {
      const char *alsa_mixer_elem_name = get_config_string(uconvert_ascii("sound", tmp1),
							   uconvert_ascii("alsa_mixer_elem", tmp2),
							   "PCM");

      alsa_mixer_elem = snd_mixer_first_elem(alsa_mixer);

      while (alsa_mixer_elem) {
	 const char *name = snd_mixer_selem_get_name(alsa_mixer_elem);

	 if (strcasecmp(name, alsa_mixer_elem_name) == 0) {
	    snd_mixer_selem_get_playback_volume_range(alsa_mixer_elem, &alsa_mixer_elem_min, &alsa_mixer_elem_max);
	    alsa_mixer_allegro_ratio = (double) (alsa_mixer_elem_max - alsa_mixer_elem_min) / (double) 255;
	    break;
	 }

	 alsa_mixer_elem = snd_mixer_elem_next(alsa_mixer_elem);
      }
   }

   /* Set format variables. */
   alsa_bits = (_sound_bits == 8) ? 8 : 16;
   alsa_stereo = (_sound_stereo) ? 1 : 0;
   alsa_rate = (_sound_freq > 0) ? _sound_freq : 44100;
   alsa_signed = 0;

   format = ((alsa_bits == 16) ? SND_PCM_FORMAT_U16_NE : SND_PCM_FORMAT_U8);

   switch (format) {

      case SND_PCM_FORMAT_U8:
	 alsa_bits = 8;
	 break;

      case SND_PCM_FORMAT_U16_NE:
	 if (sizeof(short) != 2) {
	    ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format"));
	    goto Error;
	 }
	 break;

      default:
	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format"));
	 goto Error;
   }

   alsa_sample_size = (alsa_bits / 8) * (alsa_stereo ? 2 : 1);

   if (fragsize == 0) {
      unsigned int size = alsa_rate * ALSA_DEFAULT_BUFFER_MS / 1000 / numfrags;
      fragsize = 1;
      while (fragsize < size)
	 fragsize <<= 1;
   }

   snd_pcm_hw_params_malloc(&hwparams);
   snd_pcm_sw_params_malloc(&swparams);

   ALSA9_CHECK(snd_pcm_hw_params_any(pcm_handle, hwparams));
   ALSA9_CHECK(snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED));
   ALSA9_CHECK(snd_pcm_hw_params_set_format(pcm_handle, hwparams, format));
   ALSA9_CHECK(snd_pcm_hw_params_set_channels(pcm_handle, hwparams, alsa_stereo + 1));

   ALSA9_CHECK(snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &alsa_rate, NULL));
   ALSA9_CHECK(snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &fragsize, NULL));
   ALSA9_CHECK(snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &numfrags, NULL)); 

   ALSA9_CHECK(snd_pcm_hw_params(pcm_handle, hwparams));

   ALSA9_CHECK(snd_pcm_hw_params_get_period_size(hwparams, &alsa_bufsize, NULL));
   ALSA9_CHECK(snd_pcm_hw_params_get_periods(hwparams, &alsa_fragments, NULL));

   TRACE (PREFIX_I "alsa_bufsize = %ld, alsa_fragments = %d\n", alsa_bufsize, alsa_fragments);

   ALSA9_CHECK(snd_pcm_sw_params_current(pcm_handle, swparams));
   ALSA9_CHECK(snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, alsa_bufsize));
   ALSA9_CHECK(snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, fragsize));
   ALSA9_CHECK(snd_pcm_sw_params_set_xfer_align(pcm_handle, swparams, 1));
   ALSA9_CHECK(snd_pcm_sw_params(pcm_handle, swparams));

   /* Allocate mixing buffer. */
   alsa_bufdata = _AL_MALLOC_ATOMIC(alsa_bufsize * alsa_sample_size);
   if (!alsa_bufdata) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not allocate audio buffer"));
      goto Error;
   }

   /* Initialise mixer. */
   digi_alsa.voices = voices;

   if (_mixer_init(alsa_bufsize * (alsa_stereo ? 2 : 1), alsa_rate,
		   alsa_stereo, ((alsa_bits == 16) ? 1 : 0),
		   &digi_alsa.voices) != 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not init software mixer"));
      goto Error;
   }

   snd_pcm_prepare(pcm_handle);
   pdc = snd_pcm_poll_descriptors_count (pcm_handle);
   if (pdc <= 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Invalid poll descriptors count"));
      goto Error;
   }

   ufds = _AL_MALLOC(sizeof(struct pollfd) * pdc);
   if (ufds == NULL) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory for poll descriptors"));
      goto Error;
   }
   ALSA9_CHECK(snd_pcm_poll_descriptors(pcm_handle, ufds, pdc));

   poll_next = 0;

   _mix_some_samples((uintptr_t) alsa_bufdata, 0, alsa_signed);

   /* Add audio interrupt. */
   _unix_bg_man->register_func(alsa_update);

   uszprintf(alsa_desc, sizeof(alsa_desc),
	     get_config_text
	     ("Alsa 0.9, Device '%s': %d bits, %s, %d bps, %s"),
	     alsa_device, alsa_bits,
	     uconvert_ascii((alsa_signed ? "signed" : "unsigned"), tmp1),
	     alsa_rate, uconvert_ascii((alsa_stereo ? "stereo" : "mono"), tmp2));

   digi_driver->desc = alsa_desc;
   return 0;

 Error:
   if (pcm_handle) {
      snd_pcm_close(pcm_handle);
      pcm_handle = NULL;
   }

   return -1;
}
Ejemplo n.º 2
0
int main() {  
	long loops;  
	int rc,j = 0;  
	int size;  
	snd_pcm_t *handle;  
	snd_pcm_hw_params_t *params;  
	unsigned int val,val2;  
	int dir;  
	snd_pcm_uframes_t frames;  
	char *buffer;  
	FILE *fp ;
	if( (fp = fopen("sound.wav","r")) < 0)//南拳妈妈 - 你不像她.wav
		printf("open sound.wav fial\n");
	if(fseek(fp,0,SEEK_SET) < 0)
		 printf("put fp start to first error\n ");


		/* Open PCM device for playback. */  
		rc = snd_pcm_open(&handle, "default",  
				SND_PCM_STREAM_PLAYBACK, 0);  
	if (rc < 0) {  
		fprintf(stderr,  "unable to open pcm device: %s/n",  
				snd_strerror(rc));  
		exit(1);  
	}  
	/* Allocate a hardware parameters object. */  
	snd_pcm_hw_params_alloca(&params);  
	/* Fill it in with default values. */  
	snd_pcm_hw_params_any(handle, params);  
	/* Set the desired hardware parameters. */  
	/* Interleaved mode */  
	snd_pcm_hw_params_set_access(handle, params,  
			SND_PCM_ACCESS_RW_INTERLEAVED);  
	/* Signed 16-bit little-endian format */  
	snd_pcm_hw_params_set_format(handle, params,  
			SND_PCM_FORMAT_S16_LE);  
	/* Two channels (stereo) */  
	snd_pcm_hw_params_set_channels(handle, params, 1);  
	/* 44100 bits/second sampling rate (CD quality) */  
	val = 8000;  
	snd_pcm_hw_params_set_rate_near(handle, params,  
			&val, &dir);  
	/* Set period size to 32 frames. */  
	frames = 1024;  //设置的值没有反应
	snd_pcm_hw_params_set_period_size_near(handle,  params, &frames, &dir); // 
	printf("frames is %d\n",(int)frames);
	/* Write the parameters to the driver */  
	rc = snd_pcm_hw_params(handle, params);  
	if (rc < 0) {  
		fprintf(stderr,  "unable to set hw parameters: %s/n",  snd_strerror(rc));  
		exit(1);  
	}  
	/* Use a buffer large enough to hold one period */  
	snd_pcm_hw_params_get_period_size(params, &frames,  
			&dir);  
	size = frames * 2; /* 2 bytes/sample, 2 channels */  

	buffer = (char *) malloc(size);  

	/* We want to loop for 5 seconds */  
	snd_pcm_hw_params_get_period_time(params,  &val, &dir);  

	/* 5 seconds in microseconds divided by * period time */  
	loops = 10000000 / val;  
	while (loops > 0) {  
		loops--;  
		rc = fread(buffer,1, size,fp); 


		//rc = read(0,buffer,size);

		//printf("%d\n",j++); 
		if (rc == 0) {  
			fprintf(stderr, "end of file on input\n");  
			break;  
		} else if (rc != size) {  
			fprintf(stderr,  "short read: read %d bytes\n", rc);  


		}  
		//else printf("fread to buffer success\n");
		rc = snd_pcm_writei(handle, buffer, frames);  


		if (rc == -EPIPE) {  
			/* EPIPE means underrun */  
			fprintf(stderr, "underrun occurred\n");  
			snd_pcm_prepare(handle);  
		} else if (rc < 0) {  
			fprintf(stderr,  "error from writei: %s\n",  
					snd_strerror(rc));  
		}  else if (rc != (int)frames) {  
			fprintf(stderr,  "short write, write %d frames\n", rc);  
		}  
	}  
	/*******************************************************************/
	snd_pcm_drain(handle);  
	snd_pcm_close(handle);  
	free(buffer);

	fclose(fp);

	return 0;

}
Ejemplo n.º 3
0
static int alsa_init(const char *param, int *speed,
		     int *fragsize, int *fragnr, int *channels)
{
    int err, dir;
    unsigned int rate, periods;
    snd_pcm_uframes_t period_size;
    snd_pcm_hw_params_t *hwparams;

    if (!param) {
        param = "default";
    }

    snd_pcm_hw_params_alloca(&hwparams);

    if ((err = snd_pcm_open(&handle, param, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
        log_message(LOG_DEFAULT, "Playback open error for '%s': %s", param,
		    snd_strerror(err));
        return 1;
    }

    if ((err = snd_pcm_hw_params_any(handle, hwparams)) < 0) {
        log_message(LOG_DEFAULT, "Broken configuration for playback: no configurations available: %s", snd_strerror(err));
        goto fail;
    }

    if ((err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        log_message(LOG_DEFAULT, "Access type not available for playback: %s", snd_strerror(err));
        goto fail;
    }

    if ((err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16)) < 0) {
        log_message(LOG_DEFAULT, "Sample format not available for playback: %s", snd_strerror(err));
        goto fail;
    }

    if ((err = snd_pcm_hw_params_set_channels(handle, hwparams, *channels)) < 0) {
        log_message(LOG_DEFAULT, "Channels count (%i) not available for playbacks: %s", *channels, snd_strerror(err));
        goto fail;
    }

    rate = (unsigned int)*speed;
    if ((err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, 0)) < 0) {
        log_message(LOG_DEFAULT, "Rate %iHz not available for playback: %s", *speed, snd_strerror(err));
        goto fail;
    }
    if (rate != (unsigned int)*speed) {
        printf("Rate doesn't match (requested %iHz, got %iHz)", *speed, rate);
	*speed = rate;
    }

    period_size = *fragsize;
    dir = 0;
    if ((err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_size, &dir)) < 0) {
        log_message(LOG_DEFAULT, "Unable to set period size %li for playback: %s", period_size, snd_strerror(err));
        goto fail;
    }
    *fragsize = period_size;

    periods = *fragnr;
    dir = 0;
    if ((err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &periods, &dir)) < 0) {
        log_message(LOG_DEFAULT, "Unable to set periods %i for playback: %s", periods, snd_strerror(err));
        goto fail;
    }
    *fragnr = periods;

    alsa_can_pause = snd_pcm_hw_params_can_pause(hwparams);

    if ((err = snd_pcm_hw_params(handle, hwparams)) < 0) {
        log_message(LOG_DEFAULT, "Unable to set hw params for playback: %s", snd_strerror(err));
        goto fail;
    }

    alsa_bufsize = (*fragsize)*(*fragnr);
    alsa_fragsize = *fragsize;
    alsa_channels = *channels;

    return 0;

fail:
    snd_pcm_close(handle);
    handle = NULL;
    return 1;
}
Ejemplo n.º 4
0
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);
}
Ejemplo n.º 5
0
void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &device, const std::string &description, snd_config_t *config)
{
    snd_pcm_t *pcmhandle = NULL;
    if (!OpenPCMDevice(device, "", ALSA_MAX_CHANNELS, &pcmhandle, config))
        return;

    snd_pcm_info_t *pcminfo;
    snd_pcm_info_alloca(&pcminfo);
    memset(pcminfo, 0, snd_pcm_info_sizeof());

    int err = snd_pcm_info(pcmhandle, pcminfo);
    if (err < 0)
    {
        CLog::Log(LOGINFO, "CAESinkALSA - Unable to get pcm_info for \"%s\"", device.c_str());
        snd_pcm_close(pcmhandle);
    }

    int cardNr = snd_pcm_info_get_card(pcminfo);

    CAEDeviceInfo info;
    info.m_deviceName = device;
    info.m_deviceType = AEDeviceTypeFromName(device);

    if (cardNr >= 0)
    {
        /* "HDA NVidia", "HDA Intel", "HDA ATI HDMI", "SB Live! 24-bit External", ... */
        char *cardName;
        if (snd_card_get_name(cardNr, &cardName) == 0)
            info.m_displayName = cardName;

        if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 &&
                info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI")
        {
            /* We already know this is HDMI, strip it */
            info.m_displayName.erase(info.m_displayName.size()-5);
        }

        /* "CONEXANT Analog", "USB Audio", "HDMI 0", "ALC889 Digital" ... */
        std::string pcminfoName = snd_pcm_info_get_name(pcminfo);

        /*
         * Filter "USB Audio", in those cases snd_card_get_name() is more
         * meaningful already
         */
        if (pcminfoName != "USB Audio")
            info.m_displayNameExtra = pcminfoName;

        if (info.m_deviceType == AE_DEVTYPE_HDMI)
        {
            /* replace, this was likely "HDMI 0" */
            info.m_displayNameExtra = "HDMI";

            int dev = snd_pcm_info_get_device(pcminfo);

            if (dev >= 0)
            {
                /* lets see if we can get ELD info */

                snd_ctl_t *ctlhandle;
                std::stringstream sstr;
                sstr << "hw:" << cardNr;
                std::string strHwName = sstr.str();

                if (snd_ctl_open_lconf(&ctlhandle, strHwName.c_str(), 0, config) == 0)
                {
                    snd_hctl_t *hctl;
                    if (snd_hctl_open_ctl(&hctl, ctlhandle) == 0)
                    {
                        snd_hctl_load(hctl);
                        bool badHDMI = false;
                        if (!GetELD(hctl, dev, info, badHDMI))
                            CLog::Log(LOGDEBUG, "CAESinkALSA - Unable to obtain ELD information for device \"%s\" (not supported by device, or kernel older than 3.2)",
                                      device.c_str());

                        /* snd_hctl_close also closes ctlhandle */
                        snd_hctl_close(hctl);

                        // regarding data formats we don't trust ELD
                        // push all passthrough formats to the list
                        AEDataFormatList::iterator it;
                        for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
                        {
                            if (!AE_IS_RAW(i))
                                continue;
                            it = find(info.m_dataFormats.begin(), info.m_dataFormats.end(), i);
                            if (it == info.m_dataFormats.end())
                                info.m_dataFormats.push_back(i);
                        }

                        if (badHDMI)
                        {
                            /*
                             * Warn about disconnected devices, but keep them enabled
                             * Detection can go wrong on Intel, Nvidia and on all
                             * AMD (fglrx) hardware, so it is not safe to close those
                             * handles
                             */
                            CLog::Log(LOGDEBUG, "CAESinkALSA - HDMI device \"%s\" may be unconnected (no ELD data)", device.c_str());
                        }
                    }
                    else
                    {
                        snd_ctl_close(ctlhandle);
                    }
                }
            }
        }
        else if (info.m_deviceType == AE_DEVTYPE_IEC958)
        {
            /* append instead of replace, pcminfoName is useful for S/PDIF */
            if (!info.m_displayNameExtra.empty())
                info.m_displayNameExtra += ' ';
            info.m_displayNameExtra += "S/PDIF";

            info.m_dataFormats.push_back(AE_FMT_AC3);
            info.m_dataFormats.push_back(AE_FMT_DTS);
        }
        else if (info.m_displayNameExtra.empty())
        {
            /* for USB audio, it gets a bit confusing as there is
             * - "SB Live! 24-bit External"
             * - "SB Live! 24-bit External, S/PDIF"
             * so add "Analog" qualifier to the first one */
            info.m_displayNameExtra = "Analog";
        }

        /* "default" is a device that will be used for all inputs, while
         * "@" will be mangled to front/default/surroundXX as necessary */
        if (device == "@" || device == "default")
        {
            /* Make it "Default (whatever)" */
            info.m_displayName = "Default (" + info.m_displayName + (info.m_displayNameExtra.empty() ? "" : " " + info.m_displayNameExtra + ")");
            info.m_displayNameExtra = "";
        }

    }
    else
    {
        /* virtual devices: "default", "pulse", ... */
        /* description can be e.g. "PulseAudio Sound Server" - for hw devices it is
         * normally uninteresting, like "HDMI Audio Output" or "Default Audio Device",
         * so we only use it for virtual devices that have no better display name */
        info.m_displayName = description;
    }

    snd_pcm_hw_params_t *hwparams;
    snd_pcm_hw_params_alloca(&hwparams);
    memset(hwparams, 0, snd_pcm_hw_params_sizeof());

    /* ensure we can get a playback configuration for the device */
    if (snd_pcm_hw_params_any(pcmhandle, hwparams) < 0)
    {
        CLog::Log(LOGINFO, "CAESinkALSA - No playback configurations available for device \"%s\"", device.c_str());
        snd_pcm_close(pcmhandle);
        return;
    }

    /* detect the available sample rates */
    for (unsigned int *rate = ALSASampleRateList; *rate != 0; ++rate)
        if (snd_pcm_hw_params_test_rate(pcmhandle, hwparams, *rate, 0) >= 0)
            info.m_sampleRates.push_back(*rate);

    /* detect the channels available */
    int channels = 0;
    for (int i = ALSA_MAX_CHANNELS; i >= 1; --i)
    {
        /* Reopen the device if needed on the special "surroundXX" cases */
        if (info.m_deviceType == AE_DEVTYPE_PCM && (i == 8 || i == 6 || i == 4))
            OpenPCMDevice(device, "", i, &pcmhandle, config);

        if (snd_pcm_hw_params_test_channels(pcmhandle, hwparams, i) >= 0)
        {
            channels = i;
            break;
        }
    }

    if (device == "default" && channels == 2)
    {
        /* This looks like the ALSA standard default stereo dmix device, we
         * probably want to use "@" instead to get surroundXX. */
        snd_pcm_close(pcmhandle);
        EnumerateDevice(list, "@", description, config);
        return;
    }

    CAEChannelInfo alsaChannels;
    for (int i = 0; i < channels; ++i)
    {
        if (!info.m_channels.HasChannel(ALSAChannelMap[i]))
            info.m_channels += ALSAChannelMap[i];
        alsaChannels += ALSAChannelMap[i];
    }

    /* remove the channels from m_channels that we cant use */
    info.m_channels.ResolveChannels(alsaChannels);

    /* detect the PCM sample formats that are available */
    for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
    {
        if (AE_IS_RAW(i) || i == AE_FMT_MAX)
            continue;
        snd_pcm_format_t fmt = AEFormatToALSAFormat(i);
        if (fmt == SND_PCM_FORMAT_UNKNOWN)
            continue;

        if (snd_pcm_hw_params_test_format(pcmhandle, hwparams, fmt) >= 0)
            info.m_dataFormats.push_back(i);
    }

    snd_pcm_close(pcmhandle);
    list.push_back(info);
}
Ejemplo n.º 6
0
void os_TermAudio()
{
    snd_pcm_drain(handle);
    snd_pcm_close(handle);
}
Ejemplo n.º 7
0
/**************************************************************************
 * 				wodOpen				[internal]
 */
static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
{
    WINE_WAVEDEV*	        wwo;
    snd_pcm_t *                 pcm = NULL;
    snd_hctl_t *                hctl = NULL;
    snd_pcm_hw_params_t *       hw_params = NULL;
    snd_pcm_sw_params_t *       sw_params;
    snd_pcm_access_t            access;
    snd_pcm_format_t            format = -1;
    unsigned int                rate;
    unsigned int                buffer_time = 120000;
    unsigned int                period_time = 22000;
    snd_pcm_uframes_t           buffer_size;
    snd_pcm_uframes_t           period_size;
    int                         flags;
    int                         err=0;
    int                         dir=0;
    DWORD                       retcode = 0;

    TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags);
    if (lpDesc == NULL) {
	WARN("Invalid Parameter !\n");
	return MMSYSERR_INVALPARAM;
    }
    if (wDevID >= ALSA_WodNumDevs) {
	TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs);
	return MMSYSERR_BADDEVICEID;
    }

    /* only PCM format is supported so far... */
    if (!ALSA_supportedFormat(lpDesc->lpFormat)) {
	WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
	     lpDesc->lpFormat->nSamplesPerSec);
	return WAVERR_BADFORMAT;
    }

    if (dwFlags & WAVE_FORMAT_QUERY) {
	TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
	     lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
	     lpDesc->lpFormat->nSamplesPerSec);
	return MMSYSERR_NOERROR;
    }

    wwo = &WOutDev[wDevID];

    if (wwo->pcm != NULL) {
        WARN("%d already allocated\n", wDevID);
        return MMSYSERR_ALLOCATED;
    }

    if (dwFlags & WAVE_DIRECTSOUND)
        FIXME("Why are we called with DirectSound flag? It doesn't use MMSYSTEM any more\n");
        /* not supported, ignore it */
    dwFlags &= ~WAVE_DIRECTSOUND;

    flags = SND_PCM_NONBLOCK;

    if ( (err = snd_pcm_open(&pcm, wwo->pcmname, SND_PCM_STREAM_PLAYBACK, flags)) < 0)
    {
        ERR("Error open: %s\n", snd_strerror(err));
	return MMSYSERR_NOTENABLED;
    }

    if (wwo->ctlname)
    {
        err = snd_hctl_open(&hctl, wwo->ctlname, 0);
        if (err >= 0)
        {
            snd_hctl_load(hctl);
        }
        else
        {
            WARN("Could not open hctl for [%s]: %s\n", wwo->ctlname, snd_strerror(err));
            hctl = NULL;
        }
    }

    wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);

    wwo->waveDesc = *lpDesc;
    ALSA_copyFormat(lpDesc->lpFormat, &wwo->format);

    TRACE("Requested this format: %dx%dx%d %s\n",
          wwo->format.Format.nSamplesPerSec,
          wwo->format.Format.wBitsPerSample,
          wwo->format.Format.nChannels,
          ALSA_getFormat(wwo->format.Format.wFormatTag));

    if (wwo->format.Format.wBitsPerSample == 0) {
	WARN("Resetting zeroed wBitsPerSample\n");
	wwo->format.Format.wBitsPerSample = 8 *
	    (wwo->format.Format.nAvgBytesPerSec /
	     wwo->format.Format.nSamplesPerSec) /
	    wwo->format.Format.nChannels;
    }

#define EXIT_ON_ERROR(f,e,txt) do \
{ \
    int err; \
    if ( (err = (f) ) < 0) \
    { \
	WARN(txt ": %s\n", snd_strerror(err)); \
	retcode=e; \
	goto errexit; \
    } \
} while(0)

    sw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_sw_params_sizeof() );
    snd_pcm_hw_params_malloc(&hw_params);
    if (! hw_params)
    {
        retcode = MMSYSERR_NOMEM;
        goto errexit;
    }
    snd_pcm_hw_params_any(pcm, hw_params);

    access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
    if ( ( err = snd_pcm_hw_params_set_access(pcm, hw_params, access ) ) < 0) {
        WARN("mmap not available. switching to standard write.\n");
        access = SND_PCM_ACCESS_RW_INTERLEAVED;
	EXIT_ON_ERROR( snd_pcm_hw_params_set_access(pcm, hw_params, access ), MMSYSERR_INVALPARAM, "unable to set access for playback");
	wwo->write = snd_pcm_writei;
    }
    else
	wwo->write = snd_pcm_mmap_writei;

    if ((err = snd_pcm_hw_params_set_channels(pcm, hw_params, wwo->format.Format.nChannels)) < 0) {
        WARN("unable to set required channels: %d\n", wwo->format.Format.nChannels);
        EXIT_ON_ERROR( snd_pcm_hw_params_set_channels(pcm, hw_params, wwo->format.Format.nChannels ), WAVERR_BADFORMAT, "unable to set required channels" );
    }

    if ((wwo->format.Format.wFormatTag == WAVE_FORMAT_PCM) ||
        ((wwo->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
        IsEqualGUID(&wwo->format.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) {
        format = (wwo->format.Format.wBitsPerSample == 8) ? SND_PCM_FORMAT_U8 :
                 (wwo->format.Format.wBitsPerSample == 16) ? SND_PCM_FORMAT_S16_LE :
                 (wwo->format.Format.wBitsPerSample == 24) ? SND_PCM_FORMAT_S24_3LE :
                 (wwo->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_S32_LE : -1;
    } else if ((wwo->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) &&
        IsEqualGUID(&wwo->format.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){
        format = (wwo->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_FLOAT_LE : -1;
    } else {
        ERR("invalid format: %0x04x\n", wwo->format.Format.wFormatTag);
        retcode = WAVERR_BADFORMAT;
        goto errexit;
    }

    if ((err = snd_pcm_hw_params_set_format(pcm, hw_params, format)) < 0) {
        WARN("unable to set required format: %s\n", snd_pcm_format_name(format));
        EXIT_ON_ERROR( snd_pcm_hw_params_set_format(pcm, hw_params, format), WAVERR_BADFORMAT, "unable to set required format" );
    }

    rate = wwo->format.Format.nSamplesPerSec;
    dir=0;
    err = snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, &dir);
    if (err < 0) {
	WARN("Rate %d Hz not available for playback: %s\n", wwo->format.Format.nSamplesPerSec, snd_strerror(rate));
        retcode = WAVERR_BADFORMAT;
        goto errexit;
    }
    if (!ALSA_NearMatch(rate, wwo->format.Format.nSamplesPerSec)) {
        WARN("Rate doesn't match (requested %d Hz, got %d Hz)\n", wwo->format.Format.nSamplesPerSec, rate);
        retcode = WAVERR_BADFORMAT;
        goto errexit;
    }

    TRACE("Got this format: %dx%dx%d %s\n",
          wwo->format.Format.nSamplesPerSec,
          wwo->format.Format.wBitsPerSample,
          wwo->format.Format.nChannels,
          ALSA_getFormat(wwo->format.Format.wFormatTag));

    dir=0;
    EXIT_ON_ERROR( snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, &dir), MMSYSERR_INVALPARAM, "unable to set buffer time");
    dir=0;
    EXIT_ON_ERROR( snd_pcm_hw_params_set_period_time_near(pcm, hw_params, &period_time, &dir), MMSYSERR_INVALPARAM, "unable to set period time");

    EXIT_ON_ERROR( snd_pcm_hw_params(pcm, hw_params), MMSYSERR_INVALPARAM, "unable to set hw params for playback");

    err = snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir);
    err = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);

    snd_pcm_sw_params_current(pcm, sw_params);

    EXIT_ON_ERROR( snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 1), MMSYSERR_ERROR, "unable to set start threshold");
    EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence size");
    EXIT_ON_ERROR( snd_pcm_sw_params_set_avail_min(pcm, sw_params, period_size), MMSYSERR_ERROR, "unable to set avail min");
    EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence threshold");
    EXIT_ON_ERROR( snd_pcm_sw_params(pcm, sw_params), MMSYSERR_ERROR, "unable to set sw params for playback");
#undef EXIT_ON_ERROR

    snd_pcm_prepare(pcm);

    if (TRACE_ON(wave))
	ALSA_TraceParameters(hw_params, sw_params, FALSE);

    /* now, we can save all required data for later use... */

    wwo->dwBufferSize = snd_pcm_frames_to_bytes(pcm, buffer_size);
    wwo->lpQueuePtr = wwo->lpPlayPtr = wwo->lpLoopPtr = NULL;
    wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0;
    wwo->dwPartialOffset = 0;

    ALSA_InitRingMessage(&wwo->msgRing);

    wwo->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
    wwo->hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD_PTR)wDevID, 0, &(wwo->dwThreadID));
    if (wwo->hThread)
        SetThreadPriority(wwo->hThread, THREAD_PRIORITY_TIME_CRITICAL);
    else
    {
        ERR("Thread creation for the wodPlayer failed!\n");
        CloseHandle(wwo->hStartUpEvent);
        retcode = MMSYSERR_NOMEM;
        goto errexit;
    }
    WaitForSingleObject(wwo->hStartUpEvent, INFINITE);
    CloseHandle(wwo->hStartUpEvent);
    wwo->hStartUpEvent = INVALID_HANDLE_VALUE;

    TRACE("handle=%p\n", pcm);
    TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%u, nSamplesPerSec=%u, nChannels=%u nBlockAlign=%u!\n",
	  wwo->format.Format.wBitsPerSample, wwo->format.Format.nAvgBytesPerSec,
	  wwo->format.Format.nSamplesPerSec, wwo->format.Format.nChannels,
	  wwo->format.Format.nBlockAlign);

    HeapFree( GetProcessHeap(), 0, sw_params );
    wwo->pcm = pcm;
    wwo->hctl = hctl;
    if ( wwo->hw_params )
	snd_pcm_hw_params_free(wwo->hw_params);
    wwo->hw_params = hw_params;

    return wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);

errexit:
    if (pcm)
        snd_pcm_close(pcm);

    if (hctl)
    {
        snd_hctl_free(hctl);
        snd_hctl_close(hctl);
    }

    if ( hw_params )
	snd_pcm_hw_params_free(hw_params);

    HeapFree( GetProcessHeap(), 0, sw_params );
    if (wwo->msgRing.ring_buffer_size > 0)
        ALSA_DestroyRingMessage(&wwo->msgRing);

    return retcode;
}
Ejemplo n.º 8
0
int playback(char* inputFileName) {
    long loops;
    int rc;
    int size;
    snd_pcm_t *handle;
    snd_pcm_hw_params_t *params;
    unsigned int val;
    int dir;
    snd_pcm_uframes_t frames;
    char *buffer;
    int f = 0;
    if (strlen(inputFileName)) {
        f = open(inputFileName, O_RDONLY);
    }
    /* Open PCM device for playback. */
    rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
    if (rc < 0) {
        fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
        exit(1);
    }

    /* Allocate a hardware parameters object. */
    snd_pcm_hw_params_alloca(&params);

    /* Fill it in with default values. */
    snd_pcm_hw_params_any(handle, params);

    /* Set the desired hardware parameters. */

    /* Interleaved mode */
    snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);

    /* Signed 16-bit little-endian format */
    snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);

    /* Two channels (stereo) */
    snd_pcm_hw_params_set_channels(handle, params, 2);

    /* 44100 bits/second sampling rate (CD quality) */
    val = 44100;
    snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);

    /* Set period size to 32 frames. */
    frames = 32;
    snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);

    /* Write the parameters to the driver */
    rc = snd_pcm_hw_params(handle, params);
    if (rc < 0) {
        fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
        pthread_exit(NULL);
    }

    /* Use a buffer large enough to hold one period */
    snd_pcm_hw_params_get_period_size(params, &frames, &dir);
    size = frames * 4; /* 2 bytes/sample, 2 channels */
    buffer = (char *) malloc(size);

    /* We want to loop for 5 seconds */
    snd_pcm_hw_params_get_period_time(params, &val, &dir);
    /* 5 seconds in microseconds divided by
     * period time */
    loops = 10 * 30000000 / val;

    while (loops > 0) {
        loops--;
        rc = read(f, buffer, size);
        if (rc == 0) {
            fprintf(stderr, "end of file on input\n");
            break;
        } else if (rc != size) {
            fprintf(stderr, "short read: read %d bytes\n", rc);
        }
        rc = snd_pcm_writei(handle, buffer, frames);
        if (rc == -EPIPE) {
            /* EPIPE means underrun */
            fprintf(stderr, "underrun occurred\n");
            snd_pcm_prepare(handle);
        } else if (rc < 0) {
            fprintf(stderr,
                    "error from writei: %s\n",
                    snd_strerror(rc));
        } else if (rc != (int) frames) {
            fprintf(stderr, "short write, write %d frames\n", rc);
        }
    }

    snd_pcm_drain(handle);
    snd_pcm_close(handle);
    free(buffer);
    if (f)close(f);
    return 0;
}
Ejemplo n.º 9
0
void free_pcm(void* args) {
    free_pcm_args* pargs = (free_pcm_args*) args;
    snd_pcm_drain(pargs->handle);
    snd_pcm_close(pargs->handle);
    free(pargs->buffer);
}
void QAudioDeviceInfoInternal::close()
{
    if(handle)
        snd_pcm_close(handle);
    handle = 0;
}
bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
{
    // Set nearest to closest settings that do work.
    // See if what is in settings will work (return value).
    int err = 0;
    snd_pcm_t* handle;
    snd_pcm_hw_params_t *params;
    QString dev = device;

    QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput);

    if(dev.compare(QLatin1String("default")) == 0) {
#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
        dev = QLatin1String(devices.first().constData());
#else
        dev = QLatin1String("hw:0,0");
#endif
    } else {
#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
        dev = device;
#else
        int idx = 0;
        char *name;

        QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1);

        while(snd_card_get_name(idx,&name) == 0) {
            if(shortName.compare(QLatin1String(name)) == 0)
                break;
            idx++;
        }
        dev = QString(QLatin1String("hw:%1,0")).arg(idx);
#endif
    }
    if(mode == QAudio::AudioOutput) {
        err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
    } else {
        err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
    }
    if(err < 0) {
        handle = 0;
        return false;
    }

    bool testChannel = false;
    bool testCodec = false;
    bool testFreq = false;
    bool testType = false;
    bool testSize = false;

    int  dir = 0;

    snd_pcm_nonblock( handle, 0 );
    snd_pcm_hw_params_alloca( &params );
    snd_pcm_hw_params_any( handle, params );

    // set the values!
    snd_pcm_hw_params_set_channels(handle,params,format.channels());
    snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);

    err = -1;

    switch(format.sampleSize()) {
        case 8:
            if(format.sampleType() == QAudioFormat::SignedInt)
                err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
            else if(format.sampleType() == QAudioFormat::UnSignedInt)
                err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
            break;
        case 16:
            if(format.sampleType() == QAudioFormat::SignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
            } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
            }
            break;
        case 32:
            if(format.sampleType() == QAudioFormat::SignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
            } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                if(format.byteOrder() == QAudioFormat::LittleEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
                else if(format.byteOrder() == QAudioFormat::BigEndian)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
            }
    }

    // For now, just accept only audio/pcm codec
    if(!format.codec().startsWith(QLatin1String("audio/pcm"))) {
        err=-1;
    } else
        testCodec = true;

    if(err>=0 && format.channels() != -1) {
        err = snd_pcm_hw_params_test_channels(handle,params,format.channels());
        if(err>=0)
            err = snd_pcm_hw_params_set_channels(handle,params,format.channels());
        if(err>=0)
            testChannel = true;
    }

    if(err>=0 && format.frequency() != -1) {
        err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0);
        if(err>=0)
            err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
        if(err>=0)
            testFreq = true;
    }

    if((err>=0 && format.sampleSize() != -1) &&
            (format.sampleType() != QAudioFormat::Unknown)) {
        switch(format.sampleSize()) {
            case 8:
                if(format.sampleType() == QAudioFormat::SignedInt)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
                else if(format.sampleType() == QAudioFormat::UnSignedInt)
                    err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
                break;
            case 16:
                if(format.sampleType() == QAudioFormat::SignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
                } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
                }
                break;
            case 32:
                if(format.sampleType() == QAudioFormat::SignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
                } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
                    if(format.byteOrder() == QAudioFormat::LittleEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
                    else if(format.byteOrder() == QAudioFormat::BigEndian)
                        err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
                }
        }
        if(err>=0) {
            testSize = true;
            testType = true;
        }
    }
    if(err>=0)
        err = snd_pcm_hw_params(handle, params);

    if(err == 0) {
        // settings work
        // close()
        if(handle)
            snd_pcm_close(handle);
        return true;
    }
    if(handle)
        snd_pcm_close(handle);

    return false;
}
Ejemplo n.º 12
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;
}
Ejemplo n.º 13
0
 ~ALSADevice()
 {
     if (handle != 0)
         snd_pcm_close (handle);
 }
Ejemplo n.º 14
0
/* Try and find an IEC958 PCM device and mixer on card 0 and open it
 * This function is only used on older ALSA installs that don't have the
 * correct iec958 alias stuff set up, and relies on there being only
 * one IEC958 PCM device (relies IEC958 in the device name) and one IEC958
 * mixer control for doing the settings.
 */
static int
alsaspdifsink_find_pcm_device (AlsaSPDIFSink * sink)
{
  int err = -1, dev, idx, count;
  const gchar *ctl_name = "hw:0";
  const gchar *spdif_name = SND_CTL_NAME_IEC958 ("", PLAYBACK, NONE);
  int card = sink->card;
  gchar pcm_name[24];
  snd_pcm_t *pcm = NULL;
  snd_ctl_t *ctl = NULL;
  snd_ctl_card_info_t *info = NULL;
  snd_ctl_elem_list_t *clist = NULL;
  snd_ctl_elem_id_t *cid = NULL;
  snd_pcm_info_t *pinfo = NULL;

  GST_WARNING ("Opening IEC958 named device failed. Trying to autodetect");

  if ((err = snd_ctl_open (&ctl, ctl_name, card)) < 0)
    return err;

  snd_ctl_card_info_malloc (&info);
  snd_pcm_info_malloc (&pinfo);

  /* Find a mixer for IEC958 settings */
  snd_ctl_elem_list_malloc (&clist);
  if ((err = snd_ctl_elem_list (ctl, clist)) < 0)
    goto beach;

  if ((err =
          snd_ctl_elem_list_alloc_space (clist,
              snd_ctl_elem_list_get_count (clist))) < 0)
    goto beach;
  if ((err = snd_ctl_elem_list (ctl, clist)) < 0)
    goto beach;

  count = snd_ctl_elem_list_get_used (clist);
  for (idx = 0; idx < count; idx++) {
    if (strstr (snd_ctl_elem_list_get_name (clist, idx), spdif_name) != NULL)
      break;
  }
  if (idx == count) {
    /* No SPDIF mixer availble */
    err = 0;
    goto beach;
  }
  snd_ctl_elem_id_malloc (&cid);
  snd_ctl_elem_list_get_id (clist, idx, cid);

  /* Now find a PCM device for IEC 958 */
  if ((err = snd_ctl_card_info (ctl, info)) < 0)
    goto beach;
  dev = -1;
  do {
    if (snd_ctl_pcm_next_device (ctl, &dev) < 0)
      goto beach;
    if (dev < 0)
      break;                    /* No more devices */

    /* Filter for playback devices */
    snd_pcm_info_set_device (pinfo, dev);
    snd_pcm_info_set_subdevice (pinfo, 0);
    snd_pcm_info_set_stream (pinfo, SND_PCM_STREAM_PLAYBACK);
    if ((err = snd_ctl_pcm_info (ctl, pinfo)) < 0) {
      if (err != -ENOENT)
        goto beach;             /* Genuine error */

      /* Device has no playback streams */
      continue;
    }
    if (strstr (snd_pcm_info_get_name (pinfo), "IEC958") == NULL)
      continue;                 /* Not the device we are looking for */

    count = snd_pcm_info_get_subdevices_count (pinfo);
    GST_LOG_OBJECT (sink, "Device %d has %d subdevices\n", dev,
        snd_pcm_info_get_subdevices_count (pinfo));
    for (idx = 0; idx < count; idx++) {
      snd_pcm_info_set_subdevice (pinfo, idx);

      if ((err = snd_ctl_pcm_info (ctl, pinfo)) < 0)
        goto beach;

      g_assert (snd_pcm_info_get_stream (pinfo) == SND_PCM_STREAM_PLAYBACK);

      GST_LOG_OBJECT (sink, "Found playback stream on dev %d sub-d %d\n", dev,
          idx);

      /* Found a suitable PCM device, let's open it */
      g_snprintf (pcm_name, 24, "hw:%d,%d", card, dev);
      if ((err =
              snd_pcm_open (&(pcm), pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
        goto beach;

      break;
    }
  } while (pcm == NULL);

  if (pcm != NULL) {
    snd_ctl_elem_value_t *cval;
    snd_aes_iec958_t iec958;

    /* Have a PCM device and a mixer, set things up */
    snd_ctl_elem_value_malloc (&cval);
    snd_ctl_elem_value_set_id (cval, cid);
    snd_ctl_elem_value_get_iec958 (cval, &iec958);
    iec958.status[0] = IEC958_AES0_NONAUDIO;
    iec958.status[1] = IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER;
    iec958.status[2] = 0;
    iec958.status[3] = IEC958_AES3_CON_FS_48000;
    snd_ctl_elem_value_set_iec958 (cval, &iec958);
    snd_ctl_elem_value_free (cval);

    sink->pcm = pcm;
    pcm = NULL;
    err = 0;
  }

beach:
  if (pcm)
    snd_pcm_close (pcm);
  if (clist)
    snd_ctl_elem_list_clear (clist);
  if (ctl)
    snd_ctl_close (ctl);
  if (clist)
    snd_ctl_elem_list_free (clist);
  if (cid)
    snd_ctl_elem_id_free (cid);
  if (info)
    snd_ctl_card_info_free (info);
  if (pinfo)
    snd_pcm_info_free (pinfo);
  return err;
}
Ejemplo n.º 15
0
static snd_pcm_t *
alsa_open (int channels, unsigned samplerate, int realtime)
{	const char * device = "default" ;
	snd_pcm_t *alsa_dev = NULL ;
	snd_pcm_hw_params_t *hw_params ;
	snd_pcm_uframes_t buffer_size ;
	snd_pcm_uframes_t alsa_period_size, alsa_buffer_frames ;
	snd_pcm_sw_params_t *sw_params ;

	int err ;

	if (realtime)
	{	alsa_period_size = 256 ;
		alsa_buffer_frames = 3 * alsa_period_size ;
		}
	else
	{	alsa_period_size = 1024 ;
		alsa_buffer_frames = 4 * alsa_period_size ;
		} ;

	if ((err = snd_pcm_open (&alsa_dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
	{	fprintf (stderr, "cannot open audio device \"%s\" (%s)\n", device, snd_strerror (err)) ;
		goto catch_error ;
		} ;

	snd_pcm_nonblock (alsa_dev, 0) ;

	if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0)
	{	fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)) ;
		goto catch_error ;
		} ;

	if ((err = snd_pcm_hw_params_any (alsa_dev, hw_params)) < 0)
	{	fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)) ;
		goto catch_error ;
		} ;

	if ((err = snd_pcm_hw_params_set_access (alsa_dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
	{	fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)) ;
		goto catch_error ;
		} ;

	if ((err = snd_pcm_hw_params_set_format (alsa_dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0)
	{	fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)) ;
		goto catch_error ;
		} ;

	if ((err = snd_pcm_hw_params_set_rate_near (alsa_dev, hw_params, &samplerate, 0)) < 0)
	{	fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)) ;
		goto catch_error ;
		} ;

	if ((err = snd_pcm_hw_params_set_channels (alsa_dev, hw_params, channels)) < 0)
	{	fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)) ;
		goto catch_error ;
		} ;

	if ((err = snd_pcm_hw_params_set_buffer_size_near (alsa_dev, hw_params, &alsa_buffer_frames)) < 0)
	{	fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)) ;
		goto catch_error ;
		} ;

	if ((err = snd_pcm_hw_params_set_period_size_near (alsa_dev, hw_params, &alsa_period_size, 0)) < 0)
	{	fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)) ;
		goto catch_error ;
		} ;

	if ((err = snd_pcm_hw_params (alsa_dev, hw_params)) < 0)
	{	fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)) ;
		goto catch_error ;
		} ;

	/* extra check: if we have only one period, this code won't work */
	snd_pcm_hw_params_get_period_size (hw_params, &alsa_period_size, 0) ;
	snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_size) ;
	if (alsa_period_size == buffer_size)
	{	fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", alsa_period_size, buffer_size) ;
		goto catch_error ;
		} ;

	snd_pcm_hw_params_free (hw_params) ;

	if ((err = snd_pcm_sw_params_malloc (&sw_params)) != 0)
	{	fprintf (stderr, "%s: snd_pcm_sw_params_malloc: %s", __func__, snd_strerror (err)) ;
		goto catch_error ;
		} ;

	if ((err = snd_pcm_sw_params_current (alsa_dev, sw_params)) != 0)
	{	fprintf (stderr, "%s: snd_pcm_sw_params_current: %s", __func__, snd_strerror (err)) ;
		goto catch_error ;
		} ;

	/* note: set start threshold to delay start until the ring buffer is full */
	snd_pcm_sw_params_current (alsa_dev, sw_params) ;

	if ((err = snd_pcm_sw_params_set_start_threshold (alsa_dev, sw_params, buffer_size)) < 0)
	{	fprintf (stderr, "cannot set start threshold (%s)\n", snd_strerror (err)) ;
		goto catch_error ;
		} ;

	if ((err = snd_pcm_sw_params (alsa_dev, sw_params)) != 0)
	{	fprintf (stderr, "%s: snd_pcm_sw_params: %s", __func__, snd_strerror (err)) ;
		goto catch_error ;
		} ;

	snd_pcm_sw_params_free (sw_params) ;

	snd_pcm_reset (alsa_dev) ;

catch_error :

	if (err < 0 && alsa_dev != NULL)
	{	snd_pcm_close (alsa_dev) ;
		return NULL ;
		} ;

	return alsa_dev ;
} /* alsa_open */
Ejemplo n.º 16
0
void * snd_record(void* voidargs) {
    struct snd_record_args* args = (snd_record_args*) voidargs;
    *args->returnObj.state = 0;
    long loops;
    int rc;
    int size;
    snd_pcm_t *handle;
    snd_pcm_hw_params_t *params;
    unsigned int val;
    int dir;
    snd_pcm_uframes_t frames;
    uint16_t *buffer;
    int* signalNewState = args->signalNewState;
    bool continuous_capture = args->duration <= 0 ? true : false;
    /* Open PCM device for recording (capture). */
    rc = snd_pcm_open(&handle, (const char*) args->dev_name.c_str(), SND_PCM_STREAM_CAPTURE, 0);
    pthread_cleanup_push(deallocate_srarg, voidargs);
    if (rc < 0) {
        fp_err(FPOL_PCM, "unable to open pcm device: %s", snd_strerror(rc));
        fp_debug(FPOL_PCM, "dev_name: %s", (char*) args->dev_name.c_str());
        args->returnObj.errorcode = 1;
        //pthread_cleanup_pop(1);
        //return NULL;
        pthread_exit(NULL);
    }
    /* Allocate a hardware parameters object. */
    snd_pcm_hw_params_alloca(&params);

    /* Fill it in with default values. */
    snd_pcm_hw_params_any(handle, params);

    /* Set the desired hardware parameters. */

    /* Interleaved mode */
    snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);

    /* Signed 16-bit little-endian format */
    snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);

    /* Two channels (stereo) */
    snd_pcm_hw_params_set_channels(handle, params, 2);

    /* 44100 samples/second sampling rate (CD quality) */
    val = args->samplingFrequency;
    snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);

    /* Set period size to 32 frames. */
    frames = 1152; //32; //
    snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);

    /* Write the parameters to the driver */
    rc = snd_pcm_hw_params(handle, params);
    if (rc < 0) {
        fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
        std::cout << "\n" << getTime() << " snd_record: unable to set hw parameters: " << snd_strerror(rc) << "\n";
        pthread_exit(NULL);
    }

    /* Use a buffer large enough to hold one period */
    snd_pcm_hw_params_get_period_size(params, &frames, &dir);
    size = frames * 4; /* 2 bytes/sample, 2 channels */
    buffer = (uint16_t*) malloc(size);
    free_pcm_args fpa;
    fpa.handle = handle;
    fpa.buffer = buffer;
    pthread_cleanup_push(&free_pcm, (void*) &fpa);
    /* We want to loop for 5 seconds */
    snd_pcm_hw_params_get_period_time(params, &val, &dir);
    loops = args->duration * 1000000 / val;
    *args->returnObj.state = 1;
    while (*signalNewState >= 0 && (loops > 0 || continuous_capture)) {
        loops--;
        rc = snd_pcm_readi(handle, (void**) buffer, frames);
        if (rc == -EPIPE) {
            /* EPIPE means overrun */
            fprintf(stderr, "overrun occurred\n");
            snd_pcm_prepare(handle);
        } else if (rc < 0) {
            args->returnObj.error = std::string("error from read: ") + std::string(snd_strerror(rc));
            std::cout << "\n" << getTime() << " snd_record(): error from read: " << snd_strerror(rc) << "\n";
            break;
        } else if (rc != (int) frames) {
            fprintf(stderr, "short read, read %d frames\n", rc);
        }
        (*(args->periodbuffer))[*args->periodbufferfloat].initferryperiod(size, 2);
        memcpy((*args->periodbuffer)[*args->periodbufferfloat].period, buffer, (*args->periodbuffer)[*args->periodbufferfloat].length);
        (*args->periodbufferfloat)++;
        (*args->periodbufferfloat) %= *args->periodbufferlength;
        //        if (rc != size) {
        //            fprintf(stderr, "short write: wrote %d bytes\n", rc);
        //        }
    }
    snd_pcm_drain(handle);
    snd_pcm_close(handle);
    free(buffer);
    pthread_cleanup_pop(0);
    *args->returnObj.state = -1;
    pthread_cleanup_pop(0);
    return NULL;
}
Ejemplo n.º 17
0
int AlsaIO::Initialize(uint Channels, uint Samplerate, uint Fragments, uint FragmentSize, String Card) {
    this->uiChannels           = Channels;
    this->uiSamplerate         = Samplerate;
    this->uiMaxSamplesPerCycle = FragmentSize;
    this->bInterleaved         = true;

    if (HardwareParametersSupported(Channels, Samplerate, Fragments, FragmentSize)) {
        pcm_name = "hw:" + Card;
    }
    else {
        printf("Warning: your soundcard doesn't support chosen hardware parameters; ");
        printf("trying to compensate support lack with plughw...");
        fflush(stdout);
        pcm_name = "plughw:" + Card;
    }

    int err;

    snd_pcm_hw_params_alloca(&hwparams);  // Allocate the snd_pcm_hw_params_t structure on the stack.

    /* Open PCM. The last parameter of this function is the mode. */
    /* If this is set to 0, the standard mode is used. Possible   */
    /* other values are SND_PCM_NONBLOCK and SND_PCM_ASYNC.       */
    /* If SND_PCM_NONBLOCK is used, read / write access to the    */
    /* PCM device will return immediately. If SND_PCM_ASYNC is    */
    /* specified, SIGIO will be emitted whenever a period has     */
    /* been completely processed by the soundcard.                */
    if ((err = snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0)) < 0) {
        fprintf(stderr, "Error opening PCM device %s: %s\n", pcm_name.c_str(), snd_strerror(err));
        return -1;
    }

    if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
        fprintf(stderr, "Error, cannot initialize hardware parameter structure: %s.\n", snd_strerror(err));
        return -1;
    }

    /* Set access type. This can be either    */
    /* SND_PCM_ACCESS_RW_INTERLEAVED or       */
    /* SND_PCM_ACCESS_RW_NONINTERLEAVED.      */
    if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        fprintf(stderr, "Error snd_pcm_hw_params_set_access: %s.\n", snd_strerror(err));
        return -1;
    }

    /* Set sample format */
    #if WORDS_BIGENDIAN
    if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE)) < 0) {
    #else // little endian
    if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE)) < 0) {
    #endif
        fprintf(stderr, "Error setting sample format. : %s\n", snd_strerror(err));
        return -1;
    }

    int dir = 0;

    /* Set sample rate. If the exact rate is not supported */
    /* by the hardware, use nearest possible rate.         */
    #if ALSA_MAJOR > 0
    if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &Samplerate, &dir)) < 0) {
    #else
    if((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, Samplerate, &dir)) < 0) {
    #endif
        fprintf(stderr, "Error setting sample rate. : %s\n", snd_strerror(err));
        return -1;
    }

    if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, Channels)) < 0) {
        fprintf(stderr, "Error setting number of channels. : %s\n", snd_strerror(err));
        return -1;
    }

    /* Set number of periods. Periods used to be called fragments. */
    if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, Fragments, dir)) < 0) {
        fprintf(stderr, "Error setting number of periods. : %s\n", snd_strerror(err));
        return -1;
    }

    /* Set buffer size (in frames). The resulting latency is given by */
    /* latency = periodsize * periods / (rate * bytes_per_frame)     */
    if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (FragmentSize * Fragments))) < 0) {
        fprintf(stderr, "Error setting buffersize. : %s\n", snd_strerror(err));
        return -1;
    }

    /* Apply HW parameter settings to */
    /* PCM device and prepare device  */
    if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
        fprintf(stderr, "Error setting HW params. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params_malloc(&swparams) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params_malloc. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params_current(pcm_handle, swparams) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params_current. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xffffffff) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params_set_stop_threshold. : %s\n", snd_strerror(err));
        return -1;
    }

    if (snd_pcm_sw_params(pcm_handle, swparams) != 0) {
        fprintf(stderr, "Error in snd_pcm_sw_params. : %s\n", snd_strerror(err));
        return -1;
    }

    if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
        fprintf(stderr, "Error snd_pcm_prepare : %s\n", snd_strerror(err));
        return -1;
    }

    // allocate the audio output buffer
    pOutputBuffer = new int16_t[Channels * FragmentSize];
    
    this->bInitialized = true;

    return 0;
}

/**
 *  Checks if sound card supports the chosen parameters.
 *
 *  @returns  true if hardware supports it
 */
bool AlsaIO::HardwareParametersSupported(uint channels, int samplerate, uint numfragments, uint fragmentsize) {
    pcm_name = "hw:0,0";
    if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), stream, 0) < 0) return false;
    snd_pcm_hw_params_alloca(&hwparams);
    if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    #if WORDS_BIGENDIAN
    if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_BE) < 0) {
    #else // little endian
    if (snd_pcm_hw_params_test_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) {
    #endif
        snd_pcm_close(pcm_handle);
        return false;
    }
    int dir = 0;
    if (snd_pcm_hw_params_test_rate(pcm_handle, hwparams, samplerate, dir) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_channels(pcm_handle, hwparams, channels) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_periods(pcm_handle, hwparams, numfragments, dir) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }
    if (snd_pcm_hw_params_test_buffer_size(pcm_handle, hwparams, (fragmentsize * numfragments)) < 0) {
        snd_pcm_close(pcm_handle);
        return false;
    }

    snd_pcm_close(pcm_handle);
    return true;
}

void AlsaIO::Activate() {
    this->StartThread();
}

int AlsaIO::Main() {
    if (!pEngine) {
        fprintf(stderr, "AlsaIO: No Sampler Engine assigned, exiting.\n");
        exit(EXIT_FAILURE);
    }
    if (!bInitialized) {
        fprintf(stderr, "AlsaIO: Not yet intitialized, exiting.\n");
        exit(EXIT_FAILURE);
    }

    while (true) {

        // let the engine render audio for the current audio fragment
        pEngine->RenderAudio(uiMaxSamplesPerCycle);


        // check clipping in the audio sum, convert to sample_type
        // (from 32bit to 16bit sample) and copy to output buffer
        float sample_point; uint o = 0;
        for (uint s = 0; s < uiMaxSamplesPerCycle; s++) {
            for (uint c = 0; c < uiChannels; c++) {
                sample_point = pEngine->GetAudioSumBuffer(c)[s] * pEngine->Volume;
                if (sample_point < -32768.0) sample_point = -32768.0;
                if (sample_point >  32767.0) sample_point =  32767.0;
                this->pOutputBuffer[o++] = (int32_t) sample_point;
            }
        }


        // output sound
        int res = Output();
        if (res < 0) {
            fprintf(stderr, "AlsaIO: Audio output error, exiting.\n");
            exit(EXIT_FAILURE);
        }
    }
}

/**
 *  Will be called after every audio fragment cycle, to output the audio data
 *  of the current fragment to the soundcard.
 *
 *  @returns  0 on success
 */
int AlsaIO::Output() {
    int err = snd_pcm_writei(pcm_handle, pOutputBuffer, uiMaxSamplesPerCycle);
    if (err < 0) {
        fprintf(stderr, "Error snd_pcm_writei failed. : %s\n", snd_strerror(err));
        return -1;
    }
    return 0;
}

void AlsaIO::Close() {
    if (bInitialized) {
        //dmsg(0,("Stopping Alsa Thread..."));
        //StopThread();  //FIXME: commented out due to a bug in thread.cpp (StopThread() doesn't return at all)
        //dmsg(0,("OK\n"));
        if (pcm_handle) {
            //FIXME: currently commented out due to segfault
            //snd_pcm_close(pcm_handle);
            pcm_handle = NULL;
        }
        if (pOutputBuffer) {
            //FIXME: currently commented out due to segfault
            //delete[] pOutputBuffer;
            pOutputBuffer = NULL;
        }
        bInitialized = false;
    }
}

void* AlsaIO::GetInterleavedOutputBuffer() {
    return pOutputBuffer;
}

void* AlsaIO::GetChannelOutputBufer(uint Channel) {
    fprintf(stderr, "AlsaIO::GetChannelOutputBufer(): Only interleaved access allowed so far, exiting.\n");
    exit(EXIT_FAILURE);
    // just to avoid compiler warnings
    return NULL;
}
Ejemplo n.º 18
0
int pcm_open_set_device() {
    int rc;
    snd_pcm_t *handle;
    snd_pcm_hw_params_t *params;
    snd_pcm_format_t val3;
    unsigned int val, val2;
    int dir;
    snd_pcm_uframes_t frames;

    /* Open PCM device for playback. */
    //plughw:U0x46d0x825,0
    //hw:1,0
    rc = snd_pcm_open(&handle, "plughw:1,0", SND_PCM_STREAM_PLAYBACK, 0);
    if (rc < 0) {
        fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
        exit(1);
    }

    /* Allocate a hardware parameters object. */
    snd_pcm_hw_params_alloca(&params);

    /* Fill it in with default values. */
    snd_pcm_hw_params_any(handle, params);

    /* Set the desired hardware parameters. */

    /* Interleaved mode */
    snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_NONINTERLEAVED);

    /* Signed 16-bit little-endian format */
    snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);

    /* Two channels (stereo) */
    snd_pcm_hw_params_set_channels(handle, params, 2);

    /* 44100 bits/second sampling rate (CD quality) */
    val = 44100;
    snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);

    /* Write the parameters to the driver */
    rc = snd_pcm_hw_params(handle, params);
    if (rc < 0) {
        fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
        exit(1);
    }

    /* Display information about the PCM interface */

    printf("PCM handle name = '%s'\n", snd_pcm_name(handle));

    printf("PCM state = %s\n", snd_pcm_state_name(snd_pcm_state(handle)));

    snd_pcm_hw_params_get_access(params, (snd_pcm_access_t *) & val);
    printf("access type = %s\n", snd_pcm_access_name((snd_pcm_access_t) val));

    snd_pcm_hw_params_get_format(params, (snd_pcm_format_t*) & val);
    printf("format = '%s' (%s)\n", snd_pcm_format_name((snd_pcm_format_t) val), snd_pcm_format_description((snd_pcm_format_t) val));

    snd_pcm_hw_params_get_subformat(params, (snd_pcm_subformat_t *) & val);
    printf("subformat = '%s' (%s)\n", snd_pcm_subformat_name((snd_pcm_subformat_t) val), snd_pcm_subformat_description((snd_pcm_subformat_t) val));

    snd_pcm_hw_params_get_channels(params, &val);
    printf("channels = %d\n", val);

    snd_pcm_hw_params_get_rate(params, &val, &dir);
    printf("rate = %d sps\n", val);

    snd_pcm_hw_params_get_period_time(params,
            &val, &dir);
    printf("period time = %d us\n", val);

    snd_pcm_hw_params_get_period_size(params,
            &frames, &dir);
    printf("period size = %d frames\n", (int) frames);

    snd_pcm_hw_params_get_buffer_time(params,
            &val, &dir);
    printf("buffer time = %d us\n", val);

    snd_pcm_hw_params_get_buffer_size(params,
            (snd_pcm_uframes_t *) & val);
    printf("buffer size = %d frames\n", val);

    snd_pcm_hw_params_get_periods(params, &val, &dir);
    printf("periods per buffer = %d frames\n", val);

    snd_pcm_hw_params_get_rate_numden(params,
            &val, &val2);
    printf("exact rate = %d/%d bps\n", val, val2);

    val = snd_pcm_hw_params_get_sbits(params);
    printf("significant bits = %d\n", val);

    snd_pcm_hw_params_get_tick_time(params, &val, &dir);
    printf("tick time = %d us\n", val);

    val = snd_pcm_hw_params_is_batch(params);
    printf("is batch = %d\n", val);

    val = snd_pcm_hw_params_is_block_transfer(params);
    printf("is block transfer = %d\n", val);

    val = snd_pcm_hw_params_is_double(params);
    printf("is double = %d\n", val);

    val = snd_pcm_hw_params_is_half_duplex(params);
    printf("is half duplex = %d\n", val);

    val = snd_pcm_hw_params_is_joint_duplex(params);
    printf("is joint duplex = %d\n", val);

    val = snd_pcm_hw_params_can_overrange(params);
    printf("can overrange = %d\n", val);

    val = snd_pcm_hw_params_can_mmap_sample_resolution(params);
    printf("can mmap = %d\n", val);

    val = snd_pcm_hw_params_can_pause(params);
    printf("can pause = %d\n", val);

    val = snd_pcm_hw_params_can_resume(params);
    printf("can resume = %d\n", val);

    val = snd_pcm_hw_params_can_sync_start(params);
    printf("can sync start = %d\n", val);

    snd_pcm_close(handle);

    return 0;
}
Ejemplo n.º 19
0
    int set_pcm_play(FILE *fp)
    {
            int rc;
            int ret;
            int size;
            snd_pcm_t* handle; //PCI设备句柄
            snd_pcm_hw_params_t* params;//硬件信息和PCM流配置
            unsigned int val;
            int dir=0;
            snd_pcm_uframes_t frames;
            char *buffer;
            int channels=wav_header.wChannels;
            int frequency=wav_header.nSamplesPersec;
            int bit=wav_header.wBitsPerSample;
            int datablock=wav_header.wBlockAlign;
            unsigned char ch[100]; //用来存储wav文件的头信息
        
        
            
            rc=snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
            if(rc<0)
            {
                    perror("\nopen PCM device failed:");
                    exit(1);
            }


            snd_pcm_hw_params_alloca(&params); //分配params结构体
            if(rc<0)
            {
                    perror("\nsnd_pcm_hw_params_alloca:");
                    exit(1);
            }
             rc=snd_pcm_hw_params_any(handle, params);//初始化params
            if(rc<0)
            {
                    perror("\nsnd_pcm_hw_params_any:");
                    exit(1);
            }
            rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); //初始化访问权限
            if(rc<0)
            {
                    perror("\nsed_pcm_hw_set_access:");
                    exit(1);

            }

            //采样位数
            switch(bit/8)
            {
            case 1:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8);
                    break ;
            case 2:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
                    break ;
            case 3:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S24_LE);
                    break ;

            }
            rc=snd_pcm_hw_params_set_channels(handle, params, channels); //设置声道,1表示单声>道,2表示立体声
            if(rc<0)
            {
                    perror("\nsnd_pcm_hw_params_set_channels:");
                    exit(1);
            }
            val = frequency;
            rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); //设置>频率
            if(rc<0)
            {
                    perror("\nsnd_pcm_hw_params_set_rate_near:");
                    exit(1);
            }

            rc = snd_pcm_hw_params(handle, params);
            if(rc<0)
            {
            perror("\nsnd_pcm_hw_params: ");
            exit(1);
            }

            rc=snd_pcm_hw_params_get_period_size(params, &frames, &dir); /*获取周期
    长度*/
            if(rc<0)
            {
                    perror("\nsnd_pcm_hw_params_get_period_size:");
                    exit(1);
            }

            size = frames * datablock; /*4 代表数据快长度*/

            buffer =(char*)malloc(size);
        fseek(fp,58,SEEK_SET); //定位歌曲到数据区

        while (1)
            {
                    memset(buffer,0,sizeof(buffer));
                    ret = fread(buffer, 1, size, fp);
                    if(ret == 0)
                    {
                            printf("歌曲写入结束\n");
                            break;
                    }
                     else if (ret != size)
                    {
                     }
                    // 写音频数据到PCM设备
            while(ret = snd_pcm_writei(handle, buffer, frames)<0)
               {
                     usleep(2000);
                     if (ret == -EPIPE)
                    {
                      /* EPIPE means underrun */
                      fprintf(stderr, "underrun occurred\n");
                      //完成硬件参数设置,使设备准备好
                      snd_pcm_prepare(handle);
                     }
                     else if (ret < 0)
                     {
                              fprintf(stderr,
                          "error from writei: %s\n",
                          snd_strerror(ret));
                     }
                }

        }

            snd_pcm_drain(handle);
            snd_pcm_close(handle);
            free(buffer);
            return 0;
    }
Ejemplo n.º 20
0
int main() {
  long loops;
  int rc;
  int size;
  snd_pcm_t *handle;
  snd_pcm_hw_params_t *params;
  unsigned int val;
  int dir;
  snd_pcm_uframes_t frames;
  char *buffer;

  /* Open PCM device for recording (capture). */
  rc = snd_pcm_open(&handle, "default",
                    SND_PCM_STREAM_CAPTURE, 0);
  if (rc < 0) {
    fprintf(stderr,
            "unable to open pcm device: %s\n",
            snd_strerror(rc));
    exit(1);
  }

  /* Allocate a hardware parameters object. */
  snd_pcm_hw_params_alloca(&params);

  /* Fill it in with default values. */
  snd_pcm_hw_params_any(handle, params);

  /* Set the desired hardware parameters. */

  /* Interleaved mode */
  snd_pcm_hw_params_set_access(handle, params,
                      SND_PCM_ACCESS_RW_INTERLEAVED);

  /* Signed 16-bit little-endian format */
  snd_pcm_hw_params_set_format(handle, params,
                              SND_PCM_FORMAT_S16_LE);

  /* Two channels (stereo) */
  snd_pcm_hw_params_set_channels(handle, params, 2);

  /* 44100 bits/second sampling rate (CD quality) */
  val = 44100;
  snd_pcm_hw_params_set_rate_near(handle, params,
                                  &val, &dir);

  /* Set period size to 32 frames. */
  frames = 32;
  snd_pcm_hw_params_set_period_size_near(handle,
                              params, &frames, &dir);

  /* Write the parameters to the driver */
  rc = snd_pcm_hw_params(handle, params);
  if (rc < 0) {
    fprintf(stderr,
            "unable to set hw parameters: %s\n",
            snd_strerror(rc));
    exit(1);
  }

  /* Use a buffer large enough to hold one period */
  snd_pcm_hw_params_get_period_size(params,
                                      &frames, &dir);
  size = frames * 4; /* 2 bytes/sample, 2 channels */
  buffer = (char *) malloc(size);

  /* We want to loop for 5 seconds */
  snd_pcm_hw_params_get_period_time(params,
                                         &val, &dir);
  loops = 5000000 / val;

  while (loops > 0) {
    loops--;
    rc = snd_pcm_readi(handle, buffer, frames);
    if (rc == -EPIPE) {
      /* EPIPE means overrun */
      fprintf(stderr, "overrun occurred\n");
      snd_pcm_prepare(handle);
    } else if (rc < 0) {
      fprintf(stderr,
              "error from read: %s\n",
              snd_strerror(rc));
    } else if (rc != (int)frames) {
      fprintf(stderr, "short read, read %d frames\n", rc);
    }
    rc = write(1, buffer, size);
    if (rc != size)
      fprintf(stderr,
              "short write: wrote %d bytes\n", rc);
  }

  snd_pcm_drain(handle);
  snd_pcm_close(handle);
  free(buffer);

  return 0;
}
Ejemplo n.º 21
0
static int
laudio_alsa_open(void)
{
  snd_pcm_hw_params_t *hw_params;
  snd_pcm_uframes_t bufsize;
  snd_pcm_uframes_t period_size;
  int ret;

  hw_params = NULL;

  ret = snd_pcm_open(&hdl, card_name, SND_PCM_STREAM_PLAYBACK, 0);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not open playback device: %s\n", snd_strerror(ret));

      return -1;
    }

  /* HW params */
  ret = snd_pcm_hw_params_malloc(&hw_params);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not allocate hw params: %s\n", snd_strerror(ret));

      goto out_fail;
    }

  ret = snd_pcm_hw_params_any(hdl, hw_params);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not retrieve hw params: %s\n", snd_strerror(ret));

      goto out_fail;
    }

  ret = snd_pcm_hw_params_set_access(hdl, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not set access method: %s\n", snd_strerror(ret));

      goto out_fail;
    }

  ret = snd_pcm_hw_params_set_format(hdl, hw_params, SND_PCM_FORMAT_S16_LE);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not set S16LE format: %s\n", snd_strerror(ret));

      goto out_fail;
    }

  ret = snd_pcm_hw_params_set_channels(hdl, hw_params, 2);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not set stereo output: %s\n", snd_strerror(ret));

      goto out_fail;
    }

  ret = snd_pcm_hw_params_set_rate(hdl, hw_params, 44100, 0);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Hardware doesn't support 44.1 kHz: %s\n", snd_strerror(ret));

      goto out_fail;
    }

  ret = snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufsize);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not get max buffer size: %s\n", snd_strerror(ret));

      goto out_fail;
    }

  DPRINTF(E_DBG, L_LAUDIO, "Max buffer size is %lu samples\n", bufsize);

  ret = snd_pcm_hw_params_set_buffer_size_max(hdl, hw_params, &bufsize);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not set buffer size to max: %s\n", snd_strerror(ret));

      goto out_fail;
    }

  // With a small period size we seem to get underruns because the period time
  // passes before we manage to feed with samples (if the player is slightly
  // behind - especially critical during startup when the buffer is low)
  // Internet suggests period_size should be /2 bufsize, but default seems to be
  // much lower, so compromise on /4 (but not more than 65536 frames = almost 2 sec).
  period_size = bufsize / 4;
  if (period_size > 65536)
    period_size = 65536;

  ret = snd_pcm_hw_params_set_period_size_near(hdl, hw_params, &period_size, NULL);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not set period size: %s\n", snd_strerror(ret));

      goto out_fail;
    }

  DPRINTF(E_DBG, L_LAUDIO, "Buffer size is %lu samples, period size is %lu samples\n", bufsize, period_size);

  ret = snd_pcm_hw_params(hdl, hw_params);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not set hw params: %s\n", snd_strerror(ret));

      goto out_fail;
    }

  snd_pcm_hw_params_free(hw_params);
  hw_params = NULL;

  pcm_pos = 0;
  pcm_last_error = 0;
  pcm_recovery = 0;
  pcm_buf_threshold = ((bufsize - period_size) / AIRTUNES_V2_PACKET_SAMPLES) * AIRTUNES_V2_PACKET_SAMPLES;
  pcm_period_size = period_size;

  ret = mixer_open();
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not open mixer\n");

      goto out_fail;
    }

  update_status(LAUDIO_OPEN);

  return 0;

 out_fail:
  if (hw_params)
    snd_pcm_hw_params_free(hw_params);

  snd_pcm_close(hdl);
  hdl = NULL;

  return -1;
}
Ejemplo n.º 22
0
int main(int argc, char *argv[])
{
        struct option long_option[] =
        {
                {"help", 0, NULL, 'h'},
                {"pdevice", 1, NULL, 'P'},
                {"cdevice", 1, NULL, 'C'},
                {"min", 1, NULL, 'm'},
                {"max", 1, NULL, 'M'},
                {"frames", 1, NULL, 'F'},
                {"format", 1, NULL, 'f'},
                {"channels", 1, NULL, 'c'},
                {"rate", 1, NULL, 'r'},
                {"buffer", 1, NULL, 'B'},
                {"period", 1, NULL, 'E'},
                {"seconds", 1, NULL, 's'},
                {"block", 0, NULL, 'b'},
                {"poll", 0, NULL, 'p'},
                {"effect", 0, NULL, 'e'},
                {NULL, 0, NULL, 0},
        };
        snd_pcm_t *phandle, *chandle;
        char *buffer;
        int err, latency, morehelp;
        int ok;
        snd_timestamp_t p_tstamp, c_tstamp;
        ssize_t r;
        size_t frames_in, frames_out, in_max;
        int effect = 0;
        morehelp = 0;
        while (1) {
                int c;
                if ((c = getopt_long(argc, argv, "hP:C:m:M:F:f:c:r:B:E:s:bpen", long_option, NULL)) < 0)
                        break;
                switch (c) {
                case 'h':
                        morehelp++;
                        break;
                case 'P':
                        pdevice = strdup(optarg);
                        break;
                case 'C':
                        cdevice = strdup(optarg);
                        break;
                case 'm':
                        err = atoi(optarg) / 2;
                        latency_min = err >= 4 ? err : 4;
                        if (latency_max < latency_min)
                                latency_max = latency_min;
                        break;
                case 'M':
                        err = atoi(optarg) / 2;
                        latency_max = latency_min > err ? latency_min : err;
                        break;
                case 'f':
                        format = snd_pcm_format_value(optarg);
                        if (format == SND_PCM_FORMAT_UNKNOWN) {
                                printf("Unknown format, setting to default S16_LE\n");
                                format = SND_PCM_FORMAT_S16_LE;
                        }
                        break;
                case 'c':
                        err = atoi(optarg);
                        channels = err >= 1 && err < 1024 ? err : 1;
                        break;
                case 'r':
                        err = atoi(optarg);
                        rate = err >= 4000 && err < 200000 ? err : 44100;
                        break;
                case 'B':
                        err = atoi(optarg);
                        buffer_size = err >= 32 && err < 200000 ? err : 0;
                        break;
                case 'E':
                        err = atoi(optarg);
                        period_size = err >= 32 && err < 200000 ? err : 0;
                        break;
                case 's':
                        err = atoi(optarg);
                        loop_sec = err >= 1 && err <= 100000 ? err : 30;
                        break;
                case 'b':
                        block = 1;
                        break;
                case 'p':
                        use_poll = 1;
                        break;
                case 'e':
                        effect = 1;
                        break;
                case 'n':
                        resample = 0;
                        break;
                }
        }
        if (morehelp) {
                help();
                return 0;
        }
        err = snd_output_stdio_attach(&output, stdout, 0);
        if (err < 0) {
                printf("Output failed: %s\n", snd_strerror(err));
                return 0;
        }
        loop_limit = loop_sec * rate;
        latency = latency_min - 4;
        buffer = malloc((latency_max * snd_pcm_format_width(format) / 8) * 2);
        setscheduler();
        printf("Playback device is %s\n", pdevice);
        printf("Capture device is %s\n", cdevice);
        printf("Parameters are %iHz, %s, %i channels, %s mode\n", rate, snd_pcm_format_name(format), channels, block ? "blocking" : "non-blocking");
        printf("Poll mode: %s\n", use_poll ? "yes" : "no");
        printf("Loop limit is %li frames, minimum latency = %i, maximum latency = %i\n", loop_limit, latency_min * 2, latency_max * 2);
        if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, block ? 0 : SND_PCM_NONBLOCK)) < 0) {
                printf("Playback open error: %s\n", snd_strerror(err));
                return 0;
        }
        if ((err = snd_pcm_open(&chandle, cdevice, SND_PCM_STREAM_CAPTURE, block ? 0 : SND_PCM_NONBLOCK)) < 0) {
                printf("Record open error: %s\n", snd_strerror(err));
                return 0;
        }
        /* initialize the filter sweep variables */
        if (effect) {
                fs = (float) rate;
                BW = FILTER_BANDWIDTH;
                lfo = 0;
                dlfo = 2.*M_PI*FILTERSWEEP_LFO_FREQ/fs;
                x[0] = (float*) malloc(channels*sizeof(float));
                x[1] = (float*) malloc(channels*sizeof(float));
                x[2] = (float*) malloc(channels*sizeof(float));
                y[0] = (float*) malloc(channels*sizeof(float));
                y[1] = (float*) malloc(channels*sizeof(float));
                y[2] = (float*) malloc(channels*sizeof(float));
        }

        while (1) {
                frames_in = frames_out = 0;
                if (setparams(phandle, chandle, &latency) < 0)
                        break;
                showlatency(latency);
                if ((err = snd_pcm_link(chandle, phandle)) < 0) {
                        printf("Streams link error: %s\n", snd_strerror(err));
                        exit(0);
                }
                if (snd_pcm_format_set_silence(format, buffer, latency*channels) < 0) {
                        fprintf(stderr, "silence error\n");
                        break;
                }
                if (writebuf(phandle, buffer, latency, &frames_out) < 0) {
                        fprintf(stderr, "write error\n");
                        break;
                }
                if (writebuf(phandle, buffer, latency, &frames_out) < 0) {
                        fprintf(stderr, "write error\n");
                        break;
                }
                if ((err = snd_pcm_start(chandle)) < 0) {
                        printf("Go error: %s\n", snd_strerror(err));
                        exit(0);
                }
                gettimestamp(phandle, &p_tstamp);
                gettimestamp(chandle, &c_tstamp);
#if 0
                printf("Playback:\n");
                showstat(phandle, frames_out);
                printf("Capture:\n");
                showstat(chandle, frames_in);
#endif
                ok = 1;
                in_max = 0;
                while (ok && frames_in < loop_limit) {
                        if (use_poll) {
                                /* use poll to wait for next event */
                                snd_pcm_wait(chandle, 1000);
                        }
                        if ((r = readbuf(chandle, buffer, latency, &frames_in, &in_max)) < 0)
                                ok = 0;
                        else {
                                if (effect)
                                        applyeffect(buffer,r);
                                if (writebuf(phandle, buffer, r, &frames_out) < 0)
                                        ok = 0;
                        }
                }
                if (ok)
                        printf("Success\n");
                else
                        printf("Failure\n");
                printf("Playback:\n");
                showstat(phandle, frames_out);
                printf("Capture:\n");
                showstat(chandle, frames_in);
                showinmax(in_max);
                if (p_tstamp.tv_sec == p_tstamp.tv_sec &&
                    p_tstamp.tv_usec == c_tstamp.tv_usec)
                        printf("Hardware sync\n");
                snd_pcm_drop(chandle);
                snd_pcm_nonblock(phandle, 0);
                snd_pcm_drain(phandle);
                snd_pcm_nonblock(phandle, !block ? 1 : 0);
                if (ok) {
#if 1
                        printf("Playback time = %li.%i, Record time = %li.%i, diff = %li\n",
                               p_tstamp.tv_sec,
                               (int)p_tstamp.tv_usec,
                               c_tstamp.tv_sec,
                               (int)c_tstamp.tv_usec,
                               timediff(p_tstamp, c_tstamp));
#endif
                        break;
                }
                snd_pcm_unlink(chandle);
                snd_pcm_hw_free(phandle);
                snd_pcm_hw_free(chandle);
        }
        snd_pcm_close(phandle);
        snd_pcm_close(chandle);
        return 0;
}
Ejemplo n.º 23
0
/*******************************************************************************
 **
 ** Function        app_alsa_capture_loopback_open
 **
 ** Description     Open ALSA Capture channel (from loopback driver)
 **
 ** Parameters      p_open: Capture parameters
 **
 ** Returns         status
 **
 *******************************************************************************/
int app_alsa_capture_loopback_open(tAPP_ALSA_CAPTURE_OPEN *p_open)
{
    int mode = 0; /* Default is blocking */
    unsigned int nb_channels;
    int rv;
    snd_pcm_format_t format;
    snd_pcm_access_t access;

    APP_DEBUG0("Opening ALSA/Asound audio driver Capture");

    /* Sanity check if already opened */
    if (app_alsa_cb.p_capture_handle != NULL)
    {
        APP_DEBUG0("Capture was already opened");
    }

    /* check PCM Format parameter */
    format = app_alsa_get_pcm_format(p_open->format);
    if (format == SND_PCM_FORMAT_UNKNOWN)
    {
        return -1;
    }

    /* Check PCM access parameter */
    if (p_open->access == APP_ALSA_PCM_ACCESS_RW_INTERLEAVED)
    {
        access = SND_PCM_ACCESS_RW_INTERLEAVED;
    }
    else
    {
        APP_ERROR1("Unsupported PCM access:%d", p_open->access);
        return -1;
    }
    /* Check Blocking parameter */
    if (p_open->blocking == FALSE)
    {
        mode = SND_PCM_NONBLOCK;
    }

    /* check Stereo parameter */
    if (p_open->stereo)
    {
        nb_channels = 2;
    }
    else
    {
        nb_channels = 1;
    }

    /* Save the Capture open parameters */
    memcpy(&app_alsa_cb.capture_param, p_open, sizeof(app_alsa_cb.capture_param));

    /* Open ALSA driver */
    rv = snd_pcm_open(&app_alsa_cb.p_capture_handle, alsa_device_loopback,
            SND_PCM_STREAM_CAPTURE, mode);
    if (rv < 0)
    {
        APP_ERROR1("unable to open ALSA loopback device in Capture mode:%s", snd_strerror(rv));
        return rv;
    }
    APP_DEBUG0("ALSA loopback driver opened in Capture mode");

    /* Configure ALSA driver with PCM parameters */
    rv = snd_pcm_set_params(app_alsa_cb.p_capture_handle,
            format,
            access,
            nb_channels,
            p_open->sample_rate,
            1, /* SW resample */
            p_open->latency);
    if (rv)
    {
        APP_ERROR1("Unable to config ALSA device:%s", snd_strerror(rv));
        snd_pcm_close(app_alsa_cb.p_capture_handle);
        app_alsa_cb.p_capture_handle = NULL;
        return rv;
    }
    return 0;
}
Ejemplo n.º 24
0
static void dshutdown()
{
	xmp_smix_off();
	snd_pcm_close(pcm_handle);
	free(mybuffer);
}
Ejemplo n.º 25
0
int alsa_init(audiodevice_t *dev, int cardno, int pcmdev, int mixdev, boolean automix) {
	snd_ctl_t *ctl_handle;
	snd_ctl_hw_info_t *hwinfo;
	audio_alsa05_t *alsa;
	int i, j, ncards;
	snd_pcm_t *pcm_handle;
	
	/* サウンドカードが存在するかチェック */
	ncards = snd_cards();
	if (ncards < 1) {
		WARNING("No ALSA device found\n");
		return NG;
	}
	
	if (cardno == -1 && pcmdev == -1) {
		/* 最初に見つかった使用可能なカード */
		if (NULL == (hwinfo = (snd_ctl_hw_info_t *)malloc(sizeof(*hwinfo) * ncards))) {
			NOMEMERR();
			return NG;
		}
		for (i = 0; i < ncards; i++) {
			if (0 > snd_ctl_open(&ctl_handle, i)) {
				WARNING("Can't Open Card %d\n", i);
				free(hwinfo);
				return NG;
			}
			if (0 > snd_ctl_hw_info(ctl_handle, hwinfo + i)) {
				WARNING("Can't Get Card(%d) info\n", i);
				free(hwinfo);
				return NG;
			}
			snd_ctl_close(ctl_handle);
			for (j = 0; j < hwinfo[i].pcmdevs; j++) {
				//open してチェック OK なら outへ
				if (0 > snd_pcm_open(&pcm_handle, i, j, SND_PCM_OPEN_PLAYBACK)) continue;
				cardno = i; pcmdev  = j;
				snd_pcm_close(pcm_handle);
				NOTICE("ALSA Use(%d:%d) device\n", i, j);
				goto out;
			}
		}
		// 使用可能なデバイスが1つもない場合
		WARNING("Can't Get Card(%d) info\n", i);
		return NG;
	out:
		free(hwinfo);
	} else {
		/* 指定のカード */
		if (0 > snd_ctl_open(&ctl_handle, cardno)) {
			WARNING("Can't Open Card %d\n", cardno);
			return NG;
		}
		snd_ctl_close(ctl_handle);
		
		/* 指定の pcmdevice がカードの中にあるかどうか */
		if (pcmdev >= 0 && pcmdev < hwinfo[cardno].pcmdevs) {
			//opne してチェック
			if (0 > snd_pcm_open(&pcm_handle, cardno, pcmdev, SND_PCM_OPEN_PLAYBACK)) {
				WARNING("Can't Open (%d:%d)\n", cardno, pcmdev);
				return NG;
			}
			snd_pcm_close(pcm_handle);
			NOTICE("ALSA Use(%d:%d) device\n", cardno, pcmdev);
		} else {
			WARNING("Can't Open (%d:%d)\n", cardno, pcmdev);
			return NG;
		}
	}
	
	if (mixer_init(dev, cardno, mixdev, &hwinfo) < 0) {
		return NG;
	}
	
	alsa = g_new0(audio_alsa05_t, 1);
	
	alsa->card = cardno;
	alsa->pcm_dev = pcmdev;
	alsa->automixer = automix;
	
	dev->data_pcm = alsa;
	
	dev->id      = AUDIO_PCM_ALSA;
	dev->fd      = -1;
	dev->open    = audio_open;
	dev->close   = audio_close;
	dev->write   = audio_write;
	dev->mix_set = mixer_set_level;
	dev->mix_get = mixer_get_level;
	dev->exit    = alsa_exit;
	
	NOTICE("ALSA Initilize OK\n");
	return 0;
}
Ejemplo n.º 26
0
int main(int argc, char* argv[])
{
	int df, wf;
	
	if(argc<2)
	{
		printf("Usage: %s DM-file [wav-file]\n",argv[0]);
		exit(0);
	}
	dminfo=malloc(sizeof(dmarg));
	wi=malloc(sizeof(wavinfo));
	if(!dminfo||!wi)
	{
		printf("Memory Allocation Error!\n");
		exit(0);
	}		
	fp=fopen(argv[1],"rb");
	if(!fp)
	{
		printf("Error opening input file %s!\n", argv[1]);
		exit(0);
	}
	fread(dminfo,sizeof(dmarg),1,fp);
	if(dminfo->magicnum!=MAGICNUM)
	{
		printf("not a dm file!\n");
		exit(0);
	}
	if(dminfo->delta<0x10000)
		printf("DM delta value %d\n",dminfo->delta);
	else
	{
		int deltal=dminfo->delta&0xffff;
		int deltar=(dminfo->delta-deltal)/0x10000;
		printf("DM delta value %d/%d\n",deltal,deltar);
	}
	if(dminfo->mode==MODE_TYPE1)
		printf("Channel Delta Mode\n");
	if(dminfo->mode==MODE_TYPE2)
		printf("L+R L-R Mode\n");
	fread(wi,sizeof(wavinfo),1,fp);
	printf("Sample rate %dHz, %d bits, %d channels\n",wi->srate,wi->bits,wi->channel);
	printf("Length %d:%d\n",(wi->samples/wi->srate)/60,(wi->samples/wi->srate)%60);

	
	initsound(wi->srate, wi->channel);
	
	snd_pcm_prepare(pcm_handle);
	decodeDM(fp, wi, dminfo, buf, BUFFER_NUM*frames*2*wi->channel);
	snd_pcm_writei (pcm_handle, buf,  BUFFER_NUM*frames);
	snd_pcm_start(pcm_handle);	
	
	while(1)
	{
		df=decodeDM(fp, wi, dminfo, buf, BUFFER_NUM*frames*2*wi->channel);
		wf = snd_pcm_writei (pcm_handle, buf,  df);
		if(df<BUFFER_NUM*frames)
			break;
	}
	snd_pcm_drain(pcm_handle);
	snd_pcm_close(pcm_handle);
	free(buf);
}
Ejemplo n.º 27
0
int run(char *filename)
{
    capture_stop = 0;
	char *pcm_name = "default";
	int tmp, err;
	snd_pcm_info_t *info;

	snd_pcm_info_alloca(&info);

	err = snd_output_stdio_attach(&log, stderr, 0);
	assert(err >= 0);

	file_type = FORMAT_DEFAULT;
    stream = SND_PCM_STREAM_CAPTURE;
    file_type = FORMAT_WAVE;
    command = "arecord";
    start_delay = 1;

	chunk_size = -1;
	rhwparams.format = DEFAULT_FORMAT;
	rhwparams.rate = DEFAULT_SPEED;
	rhwparams.channels = 1;

    file_type = FORMAT_WAVE;

    // cdr:
    // rhwparams.format = SND_PCM_FORMAT_S16_BE;
    rhwparams.format = file_type == FORMAT_AU ? SND_PCM_FORMAT_S16_BE : SND_PCM_FORMAT_S16_LE;
    rhwparams.rate = 44100;
    rhwparams.channels = 2;

	err = snd_pcm_open(&handle, pcm_name, stream, open_mode);
	if (err < 0) {
		error(_("audio open error: %s"), snd_strerror(err));
		return 1;
	}

	if ((err = snd_pcm_info(handle, info)) < 0) {
		error(_("info error: %s"), snd_strerror(err));
		return 1;
	}

	if (nonblock) {
		err = snd_pcm_nonblock(handle, 1);
		if (err < 0) {
			error(_("nonblock setting error: %s"), snd_strerror(err));
			return 1;
		}
	}

	chunk_size = 1024;
	hwparams = rhwparams;

	audiobuf = (u_char *)malloc(1024);
	if (audiobuf == NULL) {
		error(_("not enough memory"));
		return 1;
	}

    writei_func = snd_pcm_writei;
	readi_func = snd_pcm_readi;
	writen_func = snd_pcm_writen;
	readn_func = snd_pcm_readn;


	//signal(SIGINT, signal_handler);
	//signal(SIGTERM, signal_handler);
	//signal(SIGABRT, signal_handler);
    capture(filename);

    if (fmt_rec_table[file_type].end) {
        fmt_rec_table[file_type].end(fd);
        fd = -1;
    }
	stream = -1;
	if (fd > 1) {
		close(fd);
		fd = -1;
	}
	if (handle) {
		snd_pcm_close(handle);
		handle = NULL;
	}
	//snd_pcm_close(handle);
	//free(audiobuf);
	//snd_output_close(log);
	//snd_config_update_free_global();
	return EXIT_SUCCESS;
}
Ejemplo n.º 28
0
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;
}
Ejemplo n.º 29
0
int main(int argc, char ** argv) {
    
    // Variable declaration
	int rc;
	char * buffer;
  	int buffer_size;
  	int periods_per_buffer;

  	snd_pcm_t *handle;
  	snd_pcm_hw_params_t *params;
  	snd_pcm_uframes_t frames;

  	unsigned int channels;
  	unsigned int rate;

	wav_header * wav_header_info;

  	FILE * fp;

    
    // Argument parsing
  	if (argc != 2)
	{
        printf("Incorrect usage: Enter filename of the wav file you want to play as an argument: %s filename.txt\n", argv[0]);
		return 1;
	}

    
    // Open wav file to read
	fp = fopen(argv[1], "rb");

	if (fp == NULL)
	{
		printf("ERROR: %s does not exist, or cannot be opened.\n", argv[1]);
		return 1;
	}

	wav_header_info = malloc(44);

	fread(wav_header_info, 1, 44, fp);
    

	// print_wav_header(wav_header_info);

    
    // Assign variables that were read from the wave file
	channels = wav_header_info->number_of_channels;
	rate = wav_header_info->sample_rate;
	periods_per_buffer = 2; // Down to user preference, depending on size of internal ring buffer of ALSA


  	// Open PCM device for playback
  	if ((rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) 
  	{
    	printf("ERROR: Cannot open pcm device. %s\n", snd_strerror(rc));
  	}

    
  	// Allocate hardware parameters
  	if ((rc = snd_pcm_hw_params_malloc(&params)) < 0)
  	{
  		printf("ERROR: Cannot allocate hardware parameters. %s\n", snd_strerror(rc));
  	}

    
  	// Initialize parameters with default values
  	if ((rc = snd_pcm_hw_params_any(handle, params)) < 0)
  	{
  		printf("ERROR: Cannot initialize hardware parameters. %s\n", snd_strerror(rc));
  	}


  	// Setting hardware parameters
  	if ((rc = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
  	{
  		printf("ERROR: Cannot set interleaved mode. %s\n", snd_strerror(rc));
  	}

  	if ((rc = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE)) < 0)
  	{
  		printf("ERROR: Cannot set PCM format. %s\n", snd_strerror(rc));
  	}

  	if ((rc = snd_pcm_hw_params_set_channels_near(handle, params, &channels)) < 0)
  	{
  		printf("ERROR: Cannot set number of channels. %s\n", snd_strerror(rc));
  	}

 	if ((rc = snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0)) < 0)
 	{
 		printf("ERROR: Cannot set plyabck rate. %s\n", snd_strerror(rc));
 	}

 	if ((rc = snd_pcm_hw_params(handle, params)) < 0)
 	{
 		printf("ERROR: Cannot set hardware parameters. %s\n", snd_strerror(rc));
 	}


 	// Get hardware parameters
 	if ((rc = snd_pcm_hw_params_get_period_size(params, &frames, 0)) < 0)
	{
		printf("Playback ERROR: Can't get period size. %s\n", snd_strerror(rc));
	}
	printf("Frames: %lu\n", frames);

	if ((rc = snd_pcm_hw_params_get_channels(params, &channels)) < 0)
	{
		printf("Playback ERROR: Can't get channel number. %s\n", snd_strerror(rc));
	}

	if ((rc = snd_pcm_hw_params_get_rate(params, &rate, 0)) < 0)
	{
		printf("ERROR: Cannot get rate. %s\n", snd_strerror(rc));
	}


	// Free paraemeters
	snd_pcm_hw_params_free(params);


	// Create buffer
  	buffer_size = frames * periods_per_buffer * channels * sizeof(int16_t); /* 2 bytes/sample, 2 channels */
  	buffer = (char *) malloc(buffer_size);

  	// Send info to ALSA
 	//while ((rc = read(0, buffer, buffer_size)) != 0) 
 	while (rc = fread(buffer, 1, periods_per_buffer * frames * channels * sizeof(int16_t), fp) != 0)
 	{
    	rc = snd_pcm_writei(handle, buffer, frames * periods_per_buffer);
    	if (rc == -EPIPE) 
    	{
      		fprintf(stderr, "underrun occurred\n");
      		snd_pcm_prepare(handle);
    	} 
    	else if (rc < 0) 
    	{
      		printf("ERROR: Cannot write to playback device. %s\n", strerror(rc));
    	}
  	}

  	printf("Info set: Device is now draining...\n");
  	snd_pcm_drain(handle);

  	printf("Done playing, closing connections.\n");
  	snd_pcm_close(handle);

  	free(wav_header_info);
  	free(buffer);
  	fclose(fp);

  return 0;
}
Ejemplo n.º 30
0
/*****************************************************************************
 * OpenAudioDev: open and set up the audio device and probe for capabilities
 *****************************************************************************/
static int OpenAudioDevAlsa( demux_t *p_demux, const char *psz_device )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    p_sys->p_alsa_pcm = NULL;
    snd_pcm_hw_params_t *p_hw_params = NULL;
    snd_pcm_uframes_t buffer_size;
    snd_pcm_uframes_t chunk_size;

    /* ALSA */
    int i_err;

    if( ( i_err = snd_pcm_open( &p_sys->p_alsa_pcm, psz_device,
        SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK ) ) < 0)
    {
        msg_Err( p_demux, "Cannot open ALSA audio device %s (%s)",
                 psz_device, snd_strerror( i_err ) );
        goto adev_fail;
    }

    if( ( i_err = snd_pcm_nonblock( p_sys->p_alsa_pcm, 1 ) ) < 0)
    {
        msg_Err( p_demux, "Cannot set ALSA nonblock (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Begin setting hardware parameters */

    if( ( i_err = snd_pcm_hw_params_malloc( &p_hw_params ) ) < 0 )
    {
        msg_Err( p_demux,
                 "ALSA: cannot allocate hardware parameter structure (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    if( ( i_err = snd_pcm_hw_params_any( p_sys->p_alsa_pcm, p_hw_params ) ) < 0 )
    {
        msg_Err( p_demux,
                "ALSA: cannot initialize hardware parameter structure (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Set Interleaved access */
    if( ( i_err = snd_pcm_hw_params_set_access( p_sys->p_alsa_pcm, p_hw_params, SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set access type (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Set 16 bit little endian */
    if( ( i_err = snd_pcm_hw_params_set_format( p_sys->p_alsa_pcm, p_hw_params, SND_PCM_FORMAT_S16_LE ) ) < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set sample format (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Set sample rate */
    i_err = snd_pcm_hw_params_set_rate_near( p_sys->p_alsa_pcm, p_hw_params, &p_sys->i_sample_rate, NULL );
    if( i_err < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set sample rate (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Set channels */
    unsigned int channels = p_sys->b_stereo ? 2 : 1;
    if( ( i_err = snd_pcm_hw_params_set_channels( p_sys->p_alsa_pcm, p_hw_params, channels ) ) < 0 )
    {
        channels = ( channels==1 ) ? 2 : 1;
        msg_Warn( p_demux, "ALSA: cannot set channel count (%s). "
                  "Trying with channels=%d",
                  snd_strerror( i_err ),
                  channels );
        if( ( i_err = snd_pcm_hw_params_set_channels( p_sys->p_alsa_pcm, p_hw_params, channels ) ) < 0 )
        {
            msg_Err( p_demux, "ALSA: cannot set channel count (%s)",
                     snd_strerror( i_err ) );
            goto adev_fail;
        }
        p_sys->b_stereo = ( channels == 2 );
    }

    /* Set metrics for buffer calculations later */
    unsigned int buffer_time;
    if( ( i_err = snd_pcm_hw_params_get_buffer_time_max(p_hw_params, &buffer_time, 0) ) < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot get buffer time max (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }
    if( buffer_time > 500000 ) buffer_time = 500000;

    /* Set period time */
    unsigned int period_time = buffer_time / 4;
    i_err = snd_pcm_hw_params_set_period_time_near( p_sys->p_alsa_pcm, p_hw_params, &period_time, 0 );
    if( i_err < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set period time (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Set buffer time */
    i_err = snd_pcm_hw_params_set_buffer_time_near( p_sys->p_alsa_pcm, p_hw_params, &buffer_time, 0 );
    if( i_err < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set buffer time (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Apply new hardware parameters */
    if( ( i_err = snd_pcm_hw_params( p_sys->p_alsa_pcm, p_hw_params ) ) < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set hw parameters (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Get various buffer metrics */
    snd_pcm_hw_params_get_period_size( p_hw_params, &chunk_size, 0 );
    snd_pcm_hw_params_get_buffer_size( p_hw_params, &buffer_size );
    if( chunk_size == buffer_size )
    {
        msg_Err( p_demux,
                 "ALSA: period cannot equal buffer size (%lu == %lu)",
                 chunk_size, buffer_size);
        goto adev_fail;
    }

    int bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
    int bits_per_frame = bits_per_sample * channels;

    p_sys->i_alsa_chunk_size = chunk_size;
    p_sys->i_alsa_frame_size = bits_per_frame / 8;
    p_sys->i_max_frame_size = chunk_size * bits_per_frame / 8;

    snd_pcm_hw_params_free( p_hw_params );
    p_hw_params = NULL;

    /* Prep device */
    if( ( i_err = snd_pcm_prepare( p_sys->p_alsa_pcm ) ) < 0 )
    {
        msg_Err( p_demux,
                 "ALSA: cannot prepare audio interface for use (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    snd_pcm_start( p_sys->p_alsa_pcm );

    return VLC_SUCCESS;

 adev_fail:

    if( p_hw_params ) snd_pcm_hw_params_free( p_hw_params );
    if( p_sys->p_alsa_pcm ) snd_pcm_close( p_sys->p_alsa_pcm );
    p_sys->p_alsa_pcm = NULL;

    return VLC_EGENERIC;

}