예제 #1
0
 int main(int argc, char *argv[]) 
 { 
     char *filename; 
     char *devicename = "default"; 
     int fd; 
     WAVContainer_t wav; 
     SNDPCMContainer_t playback; 
      
     if (argc != 2) { 
         fprintf(stderr, "Usage: ./lplay <file name>/n"); 
         return -1; 
     } 
      
     memset(&playback, 0x0, sizeof(playback)); 
  
     filename = argv[1]; 
     fd = open(filename, O_RDONLY); 
     if (fd < 0) { 
         fprintf(stderr, "Error open [%s]/n", filename); 
         return -1; 
     } 
      
     if (WAV_ReadHeader(fd, &wav) < 0) { 
         fprintf(stderr, "Error WAV_Parse [%s]/n", filename); 
         goto Err; 
     } 
  
     if (snd_output_stdio_attach(&playback.log, stderr, 0) < 0) {
         fprintf(stderr, "Error snd_output_stdio_attach/n"); 
         goto Err; 
     } 
  
     if (snd_pcm_open(&playback.handle, devicename, SND_PCM_STREAM_PLAYBACK, 0) < 0) { 
         fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename); 
         goto Err; 
     } 
  
     if (SNDWAV_SetParams(&playback, &wav) < 0) { 
         fprintf(stderr, "Error set_snd_pcm_params/n"); 
         goto Err; 
     } 
     snd_pcm_dump(playback.handle, playback.log); 
  
     SNDWAV_Play(&playback, &wav, fd); 
  
     snd_pcm_drain(playback.handle); 
  
     close(fd); 
     free(playback.data_buf); 
     snd_output_close(playback.log); 
     snd_pcm_close(playback.handle); 
     return 0; 
  
 Err: 
     close(fd); 
     if (playback.data_buf) free(playback.data_buf); 
     if (playback.log) snd_output_close(playback.log); 
     if (playback.handle) snd_pcm_close(playback.handle); 
     return -1; 
 } 
예제 #2
0
internal
void hhxcb_init_alsa(hhxcb_context *context, hhxcb_sound_output *sound_output)
{
    // NOTE: "hw:0,0" doesn't seem to work with alsa running on top of pulseaudio
    char *device = (char *)"default";
    // char *device = (char *)"hw:0,0";

    int err;
    snd_pcm_sframes_t frames;
    err = snd_output_stdio_attach(&context->alsa_log, stderr, 0);

    if ((err = snd_pcm_open(&context->handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
    {
            printf("Playback open error: %s\n", snd_strerror(err));
            exit(EXIT_FAILURE);
    }

    snd_pcm_hw_params_t *hwparams;
    snd_pcm_hw_params_alloca(&hwparams);

    snd_pcm_hw_params_any(context->handle, hwparams);
    snd_pcm_hw_params_set_rate_resample(context->handle, hwparams, 0);
    snd_pcm_hw_params_set_access(context->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(context->handle, hwparams, SND_PCM_FORMAT_S16_LE);
    snd_pcm_hw_params_set_channels(context->handle, hwparams, 2);
    snd_pcm_hw_params_set_rate(context->handle, hwparams, sound_output->samples_per_second, 0);
    snd_pcm_hw_params_set_period_size(context->handle, hwparams, sound_output->samples_per_second / 60, 0);
    // NOTE: restricting this buffer size too much seems to crash the game
    sound_output->secondary_buffer_size = 48000 / 2;
    snd_pcm_hw_params_set_buffer_size(context->handle, hwparams, sound_output->secondary_buffer_size);
    snd_pcm_hw_params(context->handle, hwparams);
    snd_pcm_dump(context->handle, context->alsa_log);
}
예제 #3
0
    bool record(asr_usercommand::UserCommand::Request  &req,
         asr_usercommand::UserCommand::Response &res)
{
     char *filename;
     filename="/home/turtlebot2/asr_ws/src/asr_usercommand/wav/recordfile.wav";
      char *devicename = "default"; 
        int fd; 
        WAVContainer_t wav; 
        SNDPCMContainer_t record; 
         
        memset(&record, 0x0, sizeof(record)); 
     
        remove(filename); 
        if ((fd = open(filename, O_WRONLY | O_CREAT, 0644)) == -1) { 
            fprintf(stderr, "Error open: [%s]/n", filename); 
            return false; 
        } 
     
        if (snd_output_stdio_attach(&record.log, stderr, 0) < 0) { 
            fprintf(stderr, "Error snd_output_stdio_attach/n"); 
            goto Err; 
        } 
     
        if (snd_pcm_open(&record.handle, devicename, SND_PCM_STREAM_CAPTURE, 0) < 0) { 
            fprintf(stderr, "Error snd_pcm_open [ %s]/n", devicename); 
            goto Err; 
        } 
     
        if (SNDWAV_PrepareWAVParams(&wav) < 0) { 
            fprintf(stderr, "Error SNDWAV_PrepareWAVParams/n"); 
            goto Err; 
        } 
     
        if (SNDWAV_SetParams(&record, &wav) < 0) { 
            fprintf(stderr, "Error set_snd_pcm_params/n"); 
            goto Err; 
        } 
        snd_pcm_dump(record.handle, record.log); 
     
        SNDWAV_Record(&record, &wav, fd); 
     
        snd_pcm_drain(record.handle); 
     
        close(fd); 
        free(record.data_buf); 
        snd_output_close(record.log); 
        snd_pcm_close(record.handle); 
        return true; 
     
    Err: 
        close(fd); 
        remove(filename); 
        if (record.data_buf) free(record.data_buf); 
        if (record.log) snd_output_close(record.log); 
        if (record.handle) snd_pcm_close(record.handle); 
        return false; 
}
예제 #4
0
BOOL	alsa_open_audio(BOOL use_mmap) {
	snd_pcm_hw_params_t *hwparams;
	snd_pcm_sw_params_t *swparams;
	int err;
	snd_pcm_access_t access = (use_mmap)?(SND_PCM_ACCESS_MMAP_INTERLEAVED)
		:(SND_PCM_ACCESS_RW_INTERLEAVED);
	format = (use_mmap)?(format_8):(format_16);

	if (alsa_audiodev_is_open) return TRUE;
	snd_pcm_hw_params_alloca(&hwparams);
	snd_pcm_sw_params_alloca(&swparams);

	err = snd_output_stdio_attach(&output, stdout, 0);
	if (err < 0) {
		printf("Output failed: %s\n", snd_strerror(err));
		return 0;
	}

	if ((err = snd_pcm_open(&playback_handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
		printf("Playback open error: %s\n", snd_strerror(err));
		return 0;
	}

	if ((err = set_hwparams(playback_handle, hwparams, access)) < 0) {
		printf("Setting of hwparams failed: %s\n", snd_strerror(err));
		return 0;
	}
	if ((err = set_swparams(playback_handle, swparams)) < 0) {
		printf("Setting of swparams failed: %s\n", snd_strerror(err));
		return 0;
	}
	snd_pcm_dump(playback_handle, output);

	samples = malloc((period_size * channels * snd_pcm_format_width(format)) / 8);
	if (samples == NULL) {
		printf("No enough memory\n");
		exit(EXIT_FAILURE);
	}

	areas = calloc(channels, sizeof(snd_pcm_channel_area_t));
	if (areas == NULL) {
		printf("No enough memory\n");
		exit(EXIT_FAILURE);
	}
	for (chn = 0; chn < channels; chn++) {
		areas[chn].addr = samples;
		areas[chn].first = chn * snd_pcm_format_width(format);
		areas[chn].step = channels * snd_pcm_format_width(format);
	}

	alsa_audiodev_is_open = TRUE;

	//err = snd_pcm_writei(playback_handle, samples, (period_size * channels * snd_pcm_format_width(format)) / 8);

	return TRUE;
}
예제 #5
0
파일: kcplay.c 프로젝트: danielkitta/kcio
int
main(int argc, char** argv)
{
  const char*  devname = "default";
  int          verbose = 0;
  KCFileFormat format  = KC_FORMAT_ANY;
  int          c, rc;

  while ((c = getopt(argc, argv, "a:d:f:r:t:v?")) != -1)
    switch (c)
    {
      case 'a': amplitude  = kc_parse_arg_num(optarg, 0.0, 1.0, INT16_MAX); break;
      case 'd': devname    = optarg; break;
      case 'f': basefreq   = kc_parse_arg_num(optarg, 1.0, 1 << 20, 1.0); break;
      case 'r': samplerate = kc_parse_arg_num(optarg, 1.0, 1 << 24, 1.0); break;
      case 't': format     = kc_parse_arg_format(optarg); break;
      case 'v': verbose    = 1; break;
      case '?': exit_usage();
      default:  abort();
    }

  if (optind >= argc)
    exit_usage();

  setlocale(LC_ALL, "");
  stdout_isterm = isatty(STDOUT_FILENO);

  init_audio(devname);

  if (verbose && (rc = snd_pcm_dump(audio, output)) < 0)
    exit_snd_error(rc, "dump setup");

  if (8 * basefreq > samplerate)
  {
    fprintf(stderr, "Base frequency of %u Hz is out of range at %u samples per second\n",
            basefreq, samplerate);
    exit(1);
  }
  ratescale = 3373259426u / samplerate; // 2^30 * pi / samplerate
  periodbuf = malloc(periodsize * n_channels * sizeof(int16_t));

  for (int i = optind; i < argc; ++i)
    play_kcfile(argv[i], format);

  free(periodbuf);

  if ((rc = snd_pcm_drain(audio)) < 0)
    exit_snd_error(rc, "drain");

  if ((rc = snd_pcm_close(audio)) < 0)
    exit_snd_error(rc, "close");

  return 0;
}
예제 #6
0
static void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out)
{
	snd_pcm_file_t *file = pcm->private_data;
	if (file->fname)
		snd_output_printf(out, "File PCM (file=%s)\n", file->fname);
	else
		snd_output_printf(out, "File PCM (fd=%d)\n", file->fd);
	if (pcm->setup) {
		snd_output_printf(out, "Its setup is:\n");
		snd_pcm_dump_setup(pcm, out);
	}
	snd_output_printf(out, "Slave: ");
	snd_pcm_dump(file->gen.slave, out);
}
예제 #7
0
파일: ai_alsa1x.c 프로젝트: ArcherSeven/mpv
int ai_alsa_setup(audio_in_t *ai)
{
    snd_pcm_hw_params_t *params;
    snd_pcm_sw_params_t *swparams;
    snd_pcm_uframes_t buffer_size, period_size;
    int err;
    int dir;
    unsigned int rate;

    snd_pcm_hw_params_alloca(&params);
    snd_pcm_sw_params_alloca(&swparams);

    err = snd_pcm_hw_params_any(ai->alsa.handle, params);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Broken configuration for this PCM: no configurations available.\n");
	return -1;
    }

    err = snd_pcm_hw_params_set_access(ai->alsa.handle, params,
				       SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Access type not available.\n");
	return -1;
    }

    err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Sample format not available.\n");
	return -1;
    }

    err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels);
    if (err < 0) {
	snd_pcm_hw_params_get_channels(params, &ai->channels);
	mp_tmsg(MSGT_TV, MSGL_ERR, "Channel count not available - reverting to default: %d\n",
	       ai->channels);
    } else {
	ai->channels = ai->req_channels;
    }

    dir = 0;
    rate = ai->req_samplerate;
    err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, &rate, &dir);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set samplerate.\n");
    }
    ai->samplerate = rate;

    dir = 0;
    ai->alsa.buffer_time = 1000000;
    err = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params,
						 &ai->alsa.buffer_time, &dir);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set buffer time.\n");
    }

    dir = 0;
    ai->alsa.period_time = ai->alsa.buffer_time / 4;
    err = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params,
						 &ai->alsa.period_time, &dir);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set period time.\n");
    }

    err = snd_pcm_hw_params(ai->alsa.handle, params);
    if (err < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install hardware parameters: %s", snd_strerror(err));
	snd_pcm_hw_params_dump(params, ai->alsa.log);
	return -1;
    }

    dir = -1;
    snd_pcm_hw_params_get_period_size(params, &period_size, &dir);
    snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
    ai->alsa.chunk_size = period_size;
    if (period_size == buffer_size) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Can't use period equal to buffer size (%u == %lu)\n", ai->alsa.chunk_size, (long)buffer_size);
	return -1;
    }

    snd_pcm_sw_params_current(ai->alsa.handle, swparams);
    err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size);

    err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0);
    err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size);

    if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) {
	mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install software parameters:\n");
	snd_pcm_sw_params_dump(swparams, ai->alsa.log);
	return -1;
    }

    if (mp_msg_test(MSGT_TV, MSGL_V)) {
	snd_pcm_dump(ai->alsa.handle, ai->alsa.log);
    }

    ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
    ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels;
    ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8;
    ai->samplesize = ai->alsa.bits_per_sample;
    ai->bytes_per_sample = ai->alsa.bits_per_sample/8;

    return 0;
}
예제 #8
0
static void set_params(void)
{
	snd_pcm_hw_params_t *params;
	snd_pcm_sw_params_t *swparams;
	snd_pcm_uframes_t buffer_size;
	int err;
	size_t n;
	unsigned int rate;
	snd_pcm_uframes_t start_threshold, stop_threshold;
	snd_pcm_hw_params_alloca(&params);
	snd_pcm_sw_params_alloca(&swparams);
	err = snd_pcm_hw_params_any(handle, params);
	if (err < 0) {
		error(_("Broken configuration for this PCM: no configurations available"));
		exit(EXIT_FAILURE);
	}
	else if (interleaved)
		err = snd_pcm_hw_params_set_access(handle, params,
						   SND_PCM_ACCESS_RW_INTERLEAVED);
	else
		err = snd_pcm_hw_params_set_access(handle, params,
						   SND_PCM_ACCESS_RW_NONINTERLEAVED);
	if (err < 0) {
		error(_("Access type not available"));
		exit(EXIT_FAILURE);
	}
	err = snd_pcm_hw_params_set_format(handle, params, hwparams.format);
	if (err < 0) {
		error(_("Sample format non available"));
		exit(EXIT_FAILURE);
	}
	err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels);
	if (err < 0) {
		error(_("Channels count non available"));
		exit(EXIT_FAILURE);
	}

#if 0
	err = snd_pcm_hw_params_set_periods_min(handle, params, 2);
	assert(err >= 0);
#endif
	rate = hwparams.rate;
	err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0);
	assert(err >= 0);
	if ((float)rate * 1.05 < hwparams.rate || (float)rate * 0.95 > hwparams.rate) {
		if (!quiet_mode) {
			char plugex[64];
			const char *pcmname = snd_pcm_name(handle);
			fprintf(stderr, _("Warning: rate is not accurate (requested = %iHz, got = %iHz)\n"), rate, hwparams.rate);
			if (! pcmname || strchr(snd_pcm_name(handle), ':'))
				*plugex = 0;
			else
				snprintf(plugex, sizeof(plugex), "(-Dplug:%s)",
					 snd_pcm_name(handle));
			fprintf(stderr, _("         please, try the plug plugin %s\n"),
				plugex);
		}
	}
	rate = hwparams.rate;
	if (buffer_time == 0 && buffer_frames == 0) {
		err = snd_pcm_hw_params_get_buffer_time_max(params,
							    &buffer_time, 0);
		assert(err >= 0);
		if (buffer_time > 500000)
			buffer_time = 500000;
	}
	if (period_time == 0 && period_frames == 0) {
		if (buffer_time > 0)
			period_time = buffer_time / 4;
		else
			period_frames = buffer_frames / 4;
	}
	if (period_time > 0)
		err = snd_pcm_hw_params_set_period_time_near(handle, params,
							     &period_time, 0);
	else
		err = snd_pcm_hw_params_set_period_size_near(handle, params,
							     &period_frames, 0);
	assert(err >= 0);
	if (buffer_time > 0) {
		err = snd_pcm_hw_params_set_buffer_time_near(handle, params,
							     &buffer_time, 0);
	} else {
		err = snd_pcm_hw_params_set_buffer_size_near(handle, params,
							     &buffer_frames);
	}
	assert(err >= 0);
	err = snd_pcm_hw_params(handle, params);
	if (err < 0) {
		error(_("Unable to install hw params:"));
		snd_pcm_hw_params_dump(params, log);
		exit(EXIT_FAILURE);
	}
	snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
	snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
	if (chunk_size == buffer_size) {
		error(_("Can't use period equal to buffer size (%lu == %lu)"),
		      chunk_size, buffer_size);
		exit(EXIT_FAILURE);
	}
	snd_pcm_sw_params_current(handle, swparams);
	if (avail_min < 0)
		n = chunk_size;
	else
		n = (double) rate * avail_min / 1000000;
	err = snd_pcm_sw_params_set_avail_min(handle, swparams, n);

	/* round up to closest transfer boundary */
	n = buffer_size;
	if (start_delay <= 0) {
		start_threshold = n + (double) rate * start_delay / 1000000;
	} else
		start_threshold = (double) rate * start_delay / 1000000;
	if (start_threshold < 1)
		start_threshold = 1;
	if (start_threshold > n)
		start_threshold = n;
	err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
	assert(err >= 0);
	if (stop_delay <= 0) 
		stop_threshold = buffer_size + (double) rate * stop_delay / 1000000;
	else
		stop_threshold = (double) rate * stop_delay / 1000000;
	err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
	assert(err >= 0);

	if (snd_pcm_sw_params(handle, swparams) < 0) {
		error(_("unable to install sw params:"));
		snd_pcm_sw_params_dump(swparams, log);
		exit(EXIT_FAILURE);
	}

	if (verbose)
		snd_pcm_dump(handle, log);

	bits_per_sample = snd_pcm_format_physical_width(hwparams.format);
	bits_per_frame = bits_per_sample * hwparams.channels;
	chunk_bytes = chunk_size * bits_per_frame / 8;
	audiobuf = realloc(audiobuf, chunk_bytes);
	if (audiobuf == NULL) {
		error(_("not enough memory"));
		exit(EXIT_FAILURE);
	}
	// fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size);

	/* stereo VU-meter isn't always available... */
	if (vumeter == VUMETER_STEREO) {
		if (hwparams.channels != 2 || !interleaved || verbose > 2)
			vumeter = VUMETER_MONO;
	}

	buffer_frames = buffer_size;	/* for position test */
}
예제 #9
0
int alsamm_open_audio(int rate, int blocksize)
{
  int err;
  char devname[80];
  char *cardname;
  snd_pcm_hw_params_t* hw_params;
  snd_pcm_sw_params_t* sw_params;


  /* fragsize is an old concept now use periods, used to be called fragments. */
  /* Be aware in ALSA periodsize can be in bytes, where buffersize is in frames,
     but sometimes buffersize is in bytes and periods in frames, crazy alsa...
     ...we use periodsize and buffersize in frames */

  int i;
  short* tmp_buf;
  unsigned int tmp_uint;

  snd_pcm_hw_params_alloca(&hw_params);
  snd_pcm_sw_params_alloca(&sw_params);

  /* see add_devname */
  /* first have a look which cards we can get and
     set up device infos for them */

#ifdef ALSAMM_DEBUG
  if(sys_verbose)
    post("naudioindev=%d,  nchindev=%d, naudiooutdev=%d, nchoutdev=%d,rate=%d",
         naudioindev, nchindev,naudiooutdev, nchoutdev, rate);
#endif

  /* init some structures */
  for(i=0;i < ALSA_MAXDEV;i++){
    alsa_indev[i].a_synced=alsa_outdev[i].a_synced=0;
    alsa_indev[i].a_channels=alsa_outdev[i].a_channels=-1; /* query defaults */
  }
  alsamm_inchannels = 0;
  alsamm_outchannels = 0;

  /* opening alsa debug channel */
  err = snd_output_stdio_attach(&alsa_stdout, stdout, 0);
  if (err < 0) {
    check_error(err,"attaching alsa debug Output to stdout failed");
    /*    return; no so bad ... and never should happe */
  }


  /*
     Weak failure prevention:
     first card found (out then in) is used as a reference for parameter,
     so this  set the globals and other cards hopefully don't change them
  */
  alsamm_sr = rate;

  /* set the asked buffer time (alsa buffertime in us)*/
  alsamm_buffertime = alsamm_buffersize = 0;
  if(blocksize == 0)
    alsamm_buffertime = sys_schedadvance;
  else
    alsamm_buffersize = blocksize;

  if(sys_verbose)
    post("syschedadvance=%d us(%d Samples)so buffertime max should be this=%d"
         "or sys_blocksize=%d (samples) to use buffersize=%d",
         sys_schedadvance,sys_advance_samples,alsamm_buffertime,
         blocksize,alsamm_buffersize);

  alsamm_periods = 0; /* no one wants periods setting from command line ;-) */

  for(i=0;i<alsa_noutdev;i++)
  {
        /*   post("open audio out %d, of %lx, %d",i,&alsa_device[i],
                   alsa_outdev[i].a_handle); */
      if((err = set_hwparams(alsa_outdev[i].a_handle, hw_params,
                             &(alsa_outdev[i].a_channels))) < 0)
        {
          check_error(err,"playback device hwparam_set error:");
          continue;
        }

      if((err = set_swparams(alsa_outdev[i].a_handle, sw_params,1)) < 0){
        check_error(err,"playback device swparam_set error:");
        continue;
      }

      alsamm_outchannels += alsa_outdev[i].a_channels;

      alsa_outdev[i].a_addr =
        (char **) malloc(sizeof(char *) *  alsa_outdev[i].a_channels);

      if(alsa_outdev[i].a_addr == NULL){
        check_error(errno,"playback device outaddr allocation error:");
        continue;
      }
      memset(alsa_outdev[i].a_addr, 0, sizeof(char*) * alsa_outdev[i].a_channels);

      post("playback device with %d channels and buffer_time %d us opened",
           alsa_outdev[i].a_channels, alsamm_buffertime);
    }


  for(i=0;i<alsa_nindev;i++)
    {

      if(sys_verbose)
        post("capture card %d:--------------------",i);

      if((err = set_hwparams(alsa_indev[i].a_handle, hw_params,
                               &(alsa_indev[i].a_channels))) < 0)
        {
          check_error(err,"capture device hwparam_set error:");
          continue;
        }

      alsamm_inchannels += alsa_indev[i].a_channels;

      if((err = set_swparams(alsa_indev[i].a_handle,
            sw_params,0)) < 0){
        check_error(err,"capture device swparam_set error:");
        continue;
      }

      alsa_indev[i].a_addr =
        (char **) malloc (sizeof(char*) *  alsa_indev[i].a_channels);

      if(alsa_indev[i].a_addr == NULL){
        check_error(errno,"capture device inaddr allocation error:");
        continue;
      }

      memset(alsa_indev[i].a_addr, 0, sizeof(char*) * alsa_indev[i].a_channels);

      if(sys_verbose)
        post("capture device with %d channels and buffertime %d us opened\n",
             alsa_indev[i].a_channels,alsamm_buffertime);
    }

  /* check for linked handles of input for each output*/

  for(i=0; i<(alsa_noutdev < alsa_nindev ? alsa_noutdev:alsa_nindev); i++){
    t_alsa_dev *ad = &alsa_outdev[i];

    if (alsa_outdev[i].a_devno == alsa_indev[i].a_devno){
      if ((err = snd_pcm_link (alsa_indev[i].a_handle,
                               alsa_outdev[i].a_handle)) == 0){
        alsa_indev[i].a_synced = alsa_outdev[i].a_synced = 1;
        if(sys_verbose)
          post("Linking in and outs of card %d",i);
      }
      else
        check_error(err,"could not link in and outs");
    }
  }

  /* some globals */
  sleep_time =  (float) alsamm_period_size/ (float) alsamm_sr;


#ifdef ALSAMM_DEBUG
  /* start ---------------------------- */
  if(sys_verbose)
    post("open_audio: after dacsend=%d (xruns=%d)done",dac_send,alsamm_xruns);
  alsamm_xruns = dac_send = 0; /* reset debug */

  /* start alsa in open or better in send_dacs once ??? we will see */

  for(i=0;i<alsa_noutdev;i++)
    snd_pcm_dump(alsa_outdev[i].a_handle, alsa_stdout);

  for(i=0;i<alsa_nindev;i++)
    snd_pcm_dump(alsa_indev[i].inhandle, alsa_stdout);

  fflush(stdout);
#endif

  sys_setchsr(alsamm_inchannels,  alsamm_outchannels, alsamm_sr);

  alsamm_start();

  /* report success  */
  return (0);
}
예제 #10
0
static gboolean
alsa_open (void *dp)
{
    alsa_driver * const d = dp;
    gint mf, err, pers;

    if(pcm_open_and_load_hwparams(d) < 0)
	goto out;

    // ---
    // Set non-blocking mode.
    // ---

    d->outtime = 0;

    // --
    // Set channel parameters
    // --
    if((err = snd_pcm_hw_params_set_access(d->soundfd, d->hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
	alsa_error(N_("Unable to set access"), err);
	goto out;
    }

    if((err = snd_pcm_hw_params_set_format(d->soundfd, d->hwparams,
				    (d->bits - 8) ? d->signedness16 ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U16 :
						    d->signedness8 ? SND_PCM_FORMAT_S8 : SND_PCM_FORMAT_U8) < 0)) {
	alsa_error(N_("Unable to set audio format"), err);
	goto out;
    }
    /* Handle endianess aspects. TODO! */
    switch(d->bits) {
	case 16:
	    mf = d->signedness16 ? ST_MIXER_FORMAT_S16_LE : ST_MIXER_FORMAT_U16_LE;
	    break;
	case 8:
	default:
	    mf = d->signedness8 ? ST_MIXER_FORMAT_S8 : ST_MIXER_FORMAT_U8;
	    break;
    }

    if((err = snd_pcm_hw_params_set_channels(d->soundfd, d->hwparams, d->stereo + 1)) < 0) {
	alsa_error(N_("Unable to set channels number"), err);
	goto out;
    }
    if((d->stereo)) {
	mf |= ST_MIXER_FORMAT_STEREO;
    }
    d->mf = mf;

    d->p_mixfreq = d->playrate;
    if ((err = snd_pcm_hw_params_set_rate_near(d->soundfd, d->hwparams, &(d->p_mixfreq), NULL)) < 0) {
	alsa_error(N_("Unable to set sample rate"), err);
	goto out;
    }

    if(snd_pcm_hw_params_set_buffer_size(d->soundfd, d->hwparams, 1 << d->buffer_size) < 0) {
	/* Some soundcards report wrong maximal buffer size (maybe alsa bug). So we should try
	   to downscale its value before the reporting an error. The spinbutton still may display
	   the wrong number, but actually the correct value will be implemented.*/
	while((--d->buffer_size) >= 8)
	    if(!snd_pcm_hw_params_set_buffer_size(d->soundfd, d->hwparams, 1 << d->buffer_size))
		break;
	if(d->buffer_size < 8) {
	    error_error(N_("Unable to set appropriate buffer size"));
	    goto out;
	}
    }
    pers = 1 << d->num_periods;
    if ((err = snd_pcm_hw_params_set_periods_near(d->soundfd, d->hwparams, &pers, NULL)) < 0) {
	alsa_error(N_("Unable to set periods number"), err);
	goto out;
    }
    if ((err = snd_pcm_hw_params_get_period_size(d->hwparams, &(d->p_fragsize), NULL)) < 0) {
	alsa_error(N_("Unable to get period size"), err);
	goto out;
    }

    if((err = snd_pcm_hw_params(d->soundfd, d->hwparams))) {
	alsa_error(N_("Error setting hw parameters"), err);
	goto out;
    }

    /* The following piece of code is directly c_n_p'ed from the ALSA pcm example (whith a little adopting) */
    /* get the current swparams */
    err = snd_pcm_sw_params_current(d->soundfd, d->swparams);
    if (err < 0) {
            alsa_error(N_("Unable to determine current swparams for playback"), err);
	    goto out;
    }
    /* start the transfer when the buffer is full */
    err = snd_pcm_sw_params_set_start_threshold(d->soundfd, d->swparams, d->p_fragsize);
    if (err < 0) {
            alsa_error(N_("Unable to set start threshold mode for playback"), err);
	    goto out;
    }
    /* allow the transfer when at least period_size samples can be processed */
    err = snd_pcm_sw_params_set_avail_min(d->soundfd, d->swparams, d->p_fragsize);
    if (err < 0) {
            alsa_error(N_("Unable to set avail min for playback"), err);
	    goto out;
    }
    /* align all transfers to 1 sample */
    err = snd_pcm_sw_params_set_xfer_align(d->soundfd, d->swparams, 1);
    if (err < 0) {
            alsa_error(N_("Unable to set transfer align for playback"), err);
	    goto out;
    }
    /* write the parameters to the playback device */
    err = snd_pcm_sw_params(d->soundfd, d->swparams);
    if (err < 0) {
            alsa_error(N_("Unable to set sw params for playback"), err);
	    goto out;
    }

    err = snd_pcm_prepare(d->soundfd);
    if (err < 0) {
            alsa_error(N_("Unable to prepare playback"), err);
	    goto out;
    }
    // ---
    // Get buffering parameters
    // ---
   
    if(d->verbose)
        snd_pcm_dump(d->soundfd, d->output);
    d->sndbuf = calloc((d->stereo + 1) * (d->bits / 8), d->p_fragsize);

    d->pfd = malloc(sizeof(struct pollfd));
    if ((err = snd_pcm_poll_descriptors(d->soundfd, d->pfd, 1)) < 0) {
        alsa_error(N_("Unable to obtain poll descriptors for playback"), err);
        goto out;
    }

    d->polltag = audio_poll_add(d->pfd->fd, GDK_INPUT_WRITE, alsa_poll_ready_playing, d);

    d->playtime = 0;
    d->firstpoll = TRUE;

    return TRUE;

  out:
    alsa_release(dp);
    return FALSE;
}
예제 #11
0
int alsa_init(alsa_dev_t *dev, void *ptr, void (*callback)(snd_async_handler_t *))
{
  snd_pcm_t *phandle;
  snd_pcm_t *chandle;
  
  int err;
  snd_pcm_hw_params_t *hwparams_capture, *hwparams_playback;
  snd_pcm_sw_params_t *swparams_capture, *swparams_playback;
    
  struct sched_param param;
  
  err = sched_getparam(0, &param);
  if (err < 0) {
    perror("sched_getparam():");
    exit(-1);
  }
  
  param.sched_priority = sched_get_priority_max(SCHED_FIFO);
  err = sched_setscheduler(0, SCHED_FIFO, &param);
  if (err < 0) {
    perror("sched_setscheduler():");
   exit(-1);
  }  

  snd_pcm_hw_params_alloca(&hwparams_capture);
  snd_pcm_sw_params_alloca(&swparams_capture);  
  
  snd_pcm_hw_params_alloca(&hwparams_playback);
  snd_pcm_sw_params_alloca(&swparams_playback);   
  
  err = snd_output_stdio_attach(&dev->output, stdout, 0);
  if (err < 0) {
    printf("Output failed: %s\n", snd_strerror(err));
    exit(-1);
  }  
  
  printf("Playback device is %s\n", dev->pdevice);
  printf("Stream parameters are %dHz, %s, %d channels\n", dev->rate, snd_pcm_format_name(dev->format), dev->channels);
  
  if ((err = snd_pcm_open(&phandle, dev->pdevice, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
    printf("Playback open error: %s\n", snd_strerror(err));
    exit(-1);
  }
  
  if ((err = alsa_set_hwparams(dev, phandle, hwparams_playback, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) {
    printf("Setting of hwparams_playback failed: %s\n", snd_strerror(err));
    exit(-1);
  }
  
  if ((err = alsa_set_swparams(dev, phandle, swparams_playback)) < 0) {
    printf("Setting of swparams_playback failed: %s\n", snd_strerror(err));
    exit(-1);
  }
  
  snd_pcm_dump(phandle, dev->output);  
  
  printf("Capture device is %s\n", dev->cdevice);
  
  if ((err = snd_pcm_open(&chandle, dev->cdevice, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
    printf("Capture open error: %s\n", snd_strerror(err));
    exit(-1);
  }
  
  if ((err = alsa_set_hwparams(dev, chandle, hwparams_capture, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) {
    printf("Setting of hwparams_capture failed: %s\n", snd_strerror(err));
    exit(-1);
  }
  
  if ((err = alsa_set_swparams(dev, chandle, swparams_capture)) < 0) {
    printf("Setting of swparams_capture failed: %s\n", snd_strerror(err));
    exit(-1);
  }
  
  snd_pcm_dump(chandle, dev->output);    
  
  if ((err = snd_pcm_link(phandle, chandle)) < 0)
  {
    printf("snd_pcm_link() failed: %s\n", snd_strerror(err));
    exit(-1);    
  }
  
  dev->chandle = chandle;
  dev->phandle = phandle;

  err = alsa_async_direct_loop(dev, ptr, callback);
  if (err < 0)
    printf("Transfer failed: %s\n", snd_strerror(err));  
  
  return 0;  
}
예제 #12
0
int setparams(snd_pcm_t *phandle, snd_pcm_t *chandle, int *bufsize)
{
	int err, last_bufsize = *bufsize;
	snd_pcm_hw_params_t *pt_params, *ct_params;	/* templates with rate, format and channels */
	snd_pcm_hw_params_t *p_params, *c_params;
	snd_pcm_sw_params_t *p_swparams, *c_swparams;
	snd_pcm_uframes_t size, p_size, c_size, p_psize, c_psize;
	unsigned int p_time, c_time;

	snd_pcm_hw_params_alloca(&p_params);
	snd_pcm_hw_params_alloca(&c_params);
	snd_pcm_hw_params_alloca(&pt_params);
	snd_pcm_hw_params_alloca(&ct_params);
	snd_pcm_sw_params_alloca(&p_swparams);
	snd_pcm_sw_params_alloca(&c_swparams);
	if ((err = setparams_stream(phandle, pt_params, "playback")) < 0) {
		printf("Unable to set parameters for playback stream: %s\n", snd_strerror(err));
		exit(0);
	}
	if ((err = setparams_stream(chandle, ct_params, "capture")) < 0) {
		printf("Unable to set parameters for playback stream: %s\n", snd_strerror(err));
		exit(0);
	}

      __again:
      	if (last_bufsize == *bufsize)
		*bufsize += 4;
	last_bufsize = *bufsize;
	if (*bufsize > latency_max)
		return -1;
	if ((err = setparams_bufsize(phandle, p_params, pt_params, *bufsize, "playback")) < 0) {
		printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
		exit(0);
	}
	if ((err = setparams_bufsize(chandle, c_params, ct_params, *bufsize, "capture")) < 0) {
		printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
		exit(0);
	}

	snd_pcm_hw_params_get_period_size(p_params, &size, NULL);
	if (size > *bufsize)
		*bufsize = size;
	snd_pcm_hw_params_get_period_size(c_params, &size, NULL);
	if (size > *bufsize)
		*bufsize = size;
	snd_pcm_hw_params_get_period_time(p_params, &p_time, NULL);
	snd_pcm_hw_params_get_period_time(c_params, &c_time, NULL);
	if (p_time != c_time)
		goto __again;

	snd_pcm_hw_params_get_period_size(p_params, &p_psize, NULL);
	snd_pcm_hw_params_get_buffer_size(p_params, &p_size);
	if (p_psize * 2 < p_size)
		goto __again;
	snd_pcm_hw_params_get_period_size(c_params, &c_psize, NULL);
	snd_pcm_hw_params_get_buffer_size(c_params, &c_size);
	if (c_psize * 2 < c_size)
		goto __again;

	if ((err = setparams_set(phandle, p_params, p_swparams, "playback")) < 0) {
		printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
		exit(0);
	}
	if ((err = setparams_set(chandle, c_params, c_swparams, "capture")) < 0) {
		printf("Unable to set sw parameters for playback stream: %s\n", snd_strerror(err));
		exit(0);
	}

	if ((err = snd_pcm_prepare(phandle)) < 0) {
		printf("Prepare error: %s\n", snd_strerror(err));
		exit(0);
	}

	snd_pcm_dump(phandle, output);
	snd_pcm_dump(chandle, output);
	fflush(stdout);
	return 0;
}
예제 #13
0
int ai_alsa_setup(audio_in_t *ai)
{
    snd_pcm_hw_params_t *params;
    snd_pcm_sw_params_t *swparams;
    int buffer_size;
    int err;
    unsigned int rate;

    snd_pcm_hw_params_alloca(&params);
    snd_pcm_sw_params_alloca(&swparams);

    err = snd_pcm_hw_params_any(ai->alsa.handle, params);
    if (err < 0) {
	mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PcmBrokenConfig);
	return -1;
    }
    err = snd_pcm_hw_params_set_access(ai->alsa.handle, params,
				       SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0) {
	mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableAccessType);
	return -1;
    }
    err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE);
    if (err < 0) {
	mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableSampleFmt);
	return -1;
    }
    err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels);
    if (err < 0) {
	ai->channels = snd_pcm_hw_params_get_channels(params);
	mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_UnavailableChanCount,
	       ai->channels);
    } else {
	ai->channels = ai->req_channels;
    }

    err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, ai->req_samplerate, 0);
    assert(err >= 0);
    rate = err;
    ai->samplerate = rate;

    ai->alsa.buffer_time = 1000000;
    ai->alsa.buffer_time = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params,
							       ai->alsa.buffer_time, 0);
    assert(ai->alsa.buffer_time >= 0);
    ai->alsa.period_time = ai->alsa.buffer_time / 4;
    ai->alsa.period_time = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params,
							       ai->alsa.period_time, 0);
    assert(ai->alsa.period_time >= 0);
    err = snd_pcm_hw_params(ai->alsa.handle, params);
    if (err < 0) {
	mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallHWParams);
	snd_pcm_hw_params_dump(params, ai->alsa.log);
	return -1;
    }
    ai->alsa.chunk_size = snd_pcm_hw_params_get_period_size(params, 0);
    buffer_size = snd_pcm_hw_params_get_buffer_size(params);
    if (ai->alsa.chunk_size == buffer_size) {
	mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_PeriodEqualsBufferSize, ai->alsa.chunk_size, (long)buffer_size);
	return -1;
    }
    snd_pcm_sw_params_current(ai->alsa.handle, swparams);
    err = snd_pcm_sw_params_set_sleep_min(ai->alsa.handle, swparams,0);
    assert(err >= 0);
    err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size);
    assert(err >= 0);

    err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0);
    assert(err >= 0);
    err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size);
    assert(err >= 0);

    assert(err >= 0);
    if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) {
	mp_msg(MSGT_TV, MSGL_ERR, MSGTR_MPDEMUX_AIALSA_CannotInstallSWParams);
	snd_pcm_sw_params_dump(swparams, ai->alsa.log);
	return -1;
    }

    if (mp_msg_test(MSGT_TV, MSGL_V)) {
	snd_pcm_dump(ai->alsa.handle, ai->alsa.log);
    }

    ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
    ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels;
    ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8;
    ai->samplesize = ai->alsa.bits_per_sample;
    ai->bytes_per_sample = ai->alsa.bits_per_sample/8;

    return 0;
}
예제 #14
0
static size_t
set_params(void)
{
  snd_pcm_hw_params_t *params;
  snd_pcm_sw_params_t *swparams;
  snd_pcm_uframes_t buffer_size;
  int err;
  size_t n;
  unsigned int rate;
  snd_pcm_uframes_t start_threshold, stop_threshold;
  snd_pcm_hw_params_alloca(&params);
  snd_pcm_sw_params_alloca(&swparams);
  err = snd_pcm_hw_params_any(AHandle, params);
  if (err < 0) {
    fprintf(stderr, "Broken configuration for this PCM: no configurations available");
    exit (1);
  }
  err = snd_pcm_hw_params_set_access(AHandle, params,
                                     SND_PCM_ACCESS_RW_INTERLEAVED);
  if (err < 0) {
    fprintf(stderr, "Access type not available");
    exit(1);
  }
  err = snd_pcm_hw_params_set_format(AHandle, params, DEFAULT_FORMAT);
  if (err < 0) {
    fprintf(stderr, "Sample format non available");
    exit(1);
  }
  err = snd_pcm_hw_params_set_channels(AHandle, params, CHANNELS);
  if (err < 0) {
    fprintf(stderr, "Channels count non available");
    exit(1);
  }
  rate = DEFAULT_SPEED;
  hwparams.rate=DEFAULT_SPEED;
  hwparams.format=DEFAULT_FORMAT;
  hwparams.channels=CHANNELS;
  err = snd_pcm_hw_params_set_rate_near(AHandle, params, &hwparams.rate, 0);
  assert(err >= 0);
  rate = hwparams.rate;
  if (buffer_time == 0 && buffer_frames == 0) {
    err = snd_pcm_hw_params_get_buffer_time_max(params,
                                                &buffer_time, 0);
    assert(err >= 0);
    if (buffer_time > 500000)
      buffer_time = 500000;
  }
  if (period_time == 0 && period_frames == 0) {
    if (buffer_time > 0)
      period_time = buffer_time / 4;
    else
      period_frames = buffer_frames / 4;
  }
  if (period_time > 0)
    err = snd_pcm_hw_params_set_period_time_near(AHandle, params,
                                                 &period_time, 0);
  else
    err = snd_pcm_hw_params_set_period_size_near(AHandle, params,
                                                 &period_frames, 0);
  assert(err >= 0);
  if (buffer_time > 0) {
    err = snd_pcm_hw_params_set_buffer_time_near(AHandle, params,
                                                 &buffer_time, 0);
  } else {
    err = snd_pcm_hw_params_set_buffer_size_near(AHandle, params,
                                                 &buffer_frames);
  }
  assert(err >= 0);
  monotonic = snd_pcm_hw_params_is_monotonic(params);
  can_pause = snd_pcm_hw_params_can_pause(params);
  err = snd_pcm_hw_params(AHandle, params);
  if (err < 0) {
    fprintf(stderr, "Unable to install hw params:");
    snd_pcm_hw_params_dump(params, Log);
    exit(1);
  }
  snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
  snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
  if (chunk_size == buffer_size) {
    fprintf(stderr, "Can't use period equal to buffer size (%lu == %lu)",
            chunk_size, buffer_size);
    exit(1);
  }
  snd_pcm_sw_params_current(AHandle, swparams);
  if (avail_min < 0)
    n = chunk_size;
  else
    n = (double) rate * avail_min / 1000000;
  err = snd_pcm_sw_params_set_avail_min(AHandle, swparams, n);

  /* round up to closest transfer boundary */
  n = buffer_size;
  if (start_delay <= 0) {
    start_threshold = n + (double) rate * start_delay / 1000000;
  } else
    start_threshold = (double) rate * start_delay / 1000000;
  if (start_threshold < 1)
    start_threshold = 1;
  if (start_threshold > n)
    start_threshold = n;
  err = snd_pcm_sw_params_set_start_threshold(AHandle, swparams, start_threshold);
  assert(err >= 0);
  if (stop_delay <= 0) 
    stop_threshold = buffer_size + (double) rate * stop_delay / 1000000;
  else
    stop_threshold = (double) rate * stop_delay / 1000000;
  err = snd_pcm_sw_params_set_stop_threshold(AHandle, swparams, stop_threshold);
  assert(err >= 0);

  if (snd_pcm_sw_params(AHandle, swparams) < 0) {
    fprintf(stderr, "unable to install sw params:");
    snd_pcm_sw_params_dump(swparams, Log);
    exit(1);
  }

  snd_pcm_dump(AHandle, Log);
  bits_per_sample = snd_pcm_format_physical_width(DEFAULT_FORMAT);
  bits_per_frame = bits_per_sample * hwparams.channels;
  chunk_bytes = chunk_size * bits_per_frame / 8;
  buffer_frames = buffer_size;	/* for position test */
  return chunk_bytes;
}
예제 #15
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;
}
예제 #16
0
static int alsa_open(const char *device, unsigned sample_rate, unsigned alsa_buffer, unsigned alsa_period) {
	int err;
	snd_pcm_hw_params_t *hw_params;
	snd_pcm_hw_params_alloca(&hw_params);

	// close if already open
	if (pcmp) alsa_close();

	// reset params
	alsa.rate = 0;
	alsa.period_size = 0;
	strcpy(alsa.device, device);

	if (strlen(device) > MAX_DEVICE_LEN - 4 - 1) {
		LOG_ERROR("device name too long: %s", device);
		return -1;
	}

	LOG_INFO("opening device at: %u", sample_rate);

	bool retry;
	do {
		// open device
		if ((err = snd_pcm_open(&pcmp, alsa.device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
			LOG_ERROR("playback open error: %s", snd_strerror(err));
			return err;
		}

		// init params
		memset(hw_params, 0, snd_pcm_hw_params_sizeof());
		if ((err = snd_pcm_hw_params_any(pcmp, hw_params)) < 0) {
			LOG_ERROR("hwparam init error: %s", snd_strerror(err));
			return err;
		}

		// open hw: devices without resampling, if sample rate fails try plughw: with resampling
		bool hw = !strncmp(alsa.device, "hw:", 3);
		retry = false;

		if ((err = snd_pcm_hw_params_set_rate_resample(pcmp, hw_params, !hw)) < 0) {
			LOG_ERROR("resampling setup failed: %s", snd_strerror(err));
			return err;
		}

		if ((err = snd_pcm_hw_params_set_rate(pcmp, hw_params, sample_rate, 0)) < 0) {
			if (hw) {
				strcpy(alsa.device + 4, device);
				memcpy(alsa.device, "plug", 4);
				LOG_INFO("reopening device %s in plug mode as %s for resampling", device, alsa.device);
				snd_pcm_close(pcmp);
				retry = true;
			}
		}

	} while (retry);

	// set access 
	if (!alsa.mmap || snd_pcm_hw_params_set_access(pcmp, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
		if ((err = snd_pcm_hw_params_set_access(pcmp, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
			LOG_ERROR("access type not available: %s", snd_strerror(err));
			return err;
		}
		alsa.mmap = false;
	}

	// set the sample format
	snd_pcm_format_t *fmt = alsa.format ? &alsa.format : (snd_pcm_format_t *)fmts;
	do {
		if (snd_pcm_hw_params_set_format(pcmp, hw_params, *fmt) >= 0) {
			LOG_INFO("opened device %s using format: %s sample rate: %u mmap: %u", alsa.device, snd_pcm_format_name(*fmt), sample_rate, alsa.mmap);
			alsa.format = *fmt;
			break;
		}
		if (alsa.format) {
			LOG_ERROR("unable to open audio device requested format: %s", snd_pcm_format_name(alsa.format));
			return -1;
		}
		++fmt; 
		if (*fmt == SND_PCM_FORMAT_UNKNOWN) {
			LOG_ERROR("unable to open audio device with any supported format");
			return -1;
		}
	} while (*fmt != SND_PCM_FORMAT_UNKNOWN);

	// set the output format to be used by _scale_and_pack
	switch(alsa.format) {
	case SND_PCM_FORMAT_S32_LE:
		output.format = S32_LE; break;
	case SND_PCM_FORMAT_S24_LE: 
		output.format = S24_LE; break;
	case SND_PCM_FORMAT_S24_3LE:
		output.format = S24_3LE; break;
	case SND_PCM_FORMAT_S16_LE: 
		output.format = S16_LE; break;
	default: 
		break;
	}

	// set channels
	if ((err = snd_pcm_hw_params_set_channels (pcmp, hw_params, 2)) < 0) {
		LOG_ERROR("channel count not available: %s", snd_strerror(err));
		return err;
	}

	// set period size - value of < 50 treated as period count, otherwise size in bytes
	if (alsa_period < 50) {
		unsigned count = alsa_period;
		if ((err = snd_pcm_hw_params_set_periods_near(pcmp, hw_params, &count, 0)) < 0) {
			LOG_ERROR("unable to set period count %s", snd_strerror(err));
			return err;
		}
	} else {
		snd_pcm_uframes_t size = alsa_period;
		int dir = 0;
		if ((err = snd_pcm_hw_params_set_period_size_near(pcmp, hw_params, &size, &dir)) < 0) {
			LOG_ERROR("unable to set period size %s", snd_strerror(err));
			return err;
		}
	}

	// set buffer size - value of < 500 treated as buffer time in ms, otherwise size in bytes
	if (alsa_buffer < 500) {
		unsigned time = alsa_buffer * 1000;
		int dir = 0;
		if ((err = snd_pcm_hw_params_set_buffer_time_near(pcmp, hw_params, &time, &dir)) < 0) {
			LOG_ERROR("unable to set buffer time %s", snd_strerror(err));
			return err;
		}
	} else {
		snd_pcm_uframes_t size = alsa_buffer;
		if ((err = snd_pcm_hw_params_set_buffer_size_near(pcmp, hw_params, &size)) < 0) {
			LOG_ERROR("unable to set buffer size %s", snd_strerror(err));
			return err;
		}
	}

	// get period_size
	if ((err = snd_pcm_hw_params_get_period_size(hw_params, &alsa.period_size, 0)) < 0) {
		LOG_ERROR("unable to get period size: %s", snd_strerror(err));
		return err;
	}

	// get buffer_size
	if ((err = snd_pcm_hw_params_get_buffer_size(hw_params, &alsa.buffer_size)) < 0) {
		LOG_ERROR("unable to get buffer size: %s", snd_strerror(err));
		return err;
	}

	LOG_INFO("buffer: %u period: %u -> buffer size: %u period size: %u", alsa_buffer, alsa_period, alsa.buffer_size, alsa.period_size);

	// ensure we have two buffer sizes of samples before starting output
	output.start_frames = alsa.buffer_size * 2;

	// create an intermediate buffer for non mmap case for all but NATIVE_FORMAT
	// this is used to pack samples into the output format before calling writei
	if (!alsa.mmap && !alsa.write_buf && alsa.format != NATIVE_FORMAT) {
		alsa.write_buf = malloc(alsa.buffer_size * BYTES_PER_FRAME);
		if (!alsa.write_buf) {
			LOG_ERROR("unable to malloc write_buf");
			return -1;
		}
	}

	// set params
	if ((err = snd_pcm_hw_params(pcmp, hw_params)) < 0) {
		LOG_ERROR("unable to set hw params: %s", snd_strerror(err));
		return err;
	}

	// dump info
	if (loglevel == lSDEBUG) {
		static snd_output_t *debug_output;
		snd_output_stdio_attach(&debug_output, stderr, 0);
		snd_pcm_dump(pcmp, debug_output);
	}

	// this indicates we have opened the device ok
	alsa.rate = sample_rate;

	return 0;
}