static void dump_parm(snd_pcm_hw_params_t *params)
{
	snd_output_t *log;
	snd_output_stdio_attach(&log, stderr, 0);
	snd_pcm_hw_params_dump(params, log);
	snd_output_close(log);
}
void set_hwparams(snd_pcm_t *phandle)
{
	int err;
	snd_pcm_hw_params_t *params;

	err = snd_output_stdio_attach(&log, stderr, 0);
	if (err < 0) {
		fprintf(stderr, "cannot attach output stdio\n");
		exit(0);
	}

	snd_pcm_hw_params_alloca(&params);
	err = snd_pcm_hw_params_any(phandle, params);
	if (err < 0) {
		fprintf(stderr, "Broken configuration for this PCM: no configurations available\n");
		exit(0);
	}

	err = snd_pcm_hw_params_set_access(phandle, params,
					   SND_PCM_ACCESS_RW_INTERLEAVED);
	if (err < 0) {
		fprintf(stderr, "Access type not available\n");
		exit(0);
	}
	err = snd_pcm_hw_params_set_format(phandle, params, SND_PCM_FORMAT_S16_LE);
	if (err < 0) {
		fprintf(stderr, "cannot set format\n");
		exit(0);
	}
	err = snd_pcm_hw_params_set_channels(phandle, params, 2);
	if (err < 0) {
		fprintf(stderr, "cannot set channels 2\n");
		exit(0);
	}
	err = snd_pcm_hw_params_set_rate_near(phandle, params, 44100, 0);
	if (err < 0) {
		fprintf(stderr, "cannot set rate\n");
		exit(0);
	}
	err = snd_pcm_hw_params_set_period_size_near(phandle, params, period_size);
	if (err < 0) {
		fprintf(stderr, "cannot set period size\n");
		exit(0);
	}
	err = snd_pcm_hw_params(phandle, params);
	if (err < 0) {
		fprintf(stderr, "Unable to install hw params:\n");
		exit(0);
	}
	snd_pcm_hw_params_dump(params, log);
}
Ejemplo n.º 3
0
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;
}
Ejemplo n.º 4
0
Archivo: alsa.c Proyecto: DEGAUSSE/alsa
void *capture_thread(void *data) {
  AudioCapture *capture = (AudioCapture *)data;
  // enif_keep_resource(capture);
  
  detect_pcm(capture);
  
  set_volume(capture, 100);
  
  snd_pcm_open(&capture->handle, capture->pcm_name, SND_PCM_STREAM_CAPTURE, 0);
  if(!capture->handle) {
    fprintf(stderr, "No PCM!!\r\n");
    exit(1);
  }
  snd_pcm_hw_params_t *hw_params;
  snd_pcm_hw_params_malloc(&hw_params);
  if(!hw_params) {
    fprintf(stderr, "Damn!! No hw_params\r\n");
    exit(1);
  }
  
  snd_pcm_hw_params_any(capture->handle, hw_params);
  snd_pcm_hw_params_set_access(capture->handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
  snd_pcm_hw_params_set_format(capture->handle, hw_params, SND_PCM_FORMAT_S16_LE);
  snd_pcm_hw_params_set_rate_near(capture->handle, hw_params, &capture->sample_rate, 0);
  snd_pcm_hw_params_set_channels(capture->handle, hw_params, capture->channels);
  
  // int buffer_size = 16384;
  // int period_time = 32000;
  // int period_size = 1024;
  // snd_pcm_hw_params_set_period_time_near(capture->handle, hw_params, &period_time, 0);
  // snd_pcm_hw_params_set_period_size_near(capture->handle, hw_params, &period_size, 0);
  //  snd_pcm_hw_params_set_buffer_size_near(capture->handle, hw_params, &buffer_size);
  //  
	
  capture->last_dts = 0;
  
  fprintf(stderr, "Setting params: %p, %p\r\n", capture->handle, hw_params);
  
  snd_pcm_hw_params(capture->handle, hw_params);
	snd_pcm_hw_params_free(hw_params);
  snd_pcm_prepare(capture->handle);
  
  snd_output_t *log;
  snd_output_stdio_attach(&log, stderr, 0);
  snd_pcm_hw_params_dump(hw_params, log);
  
  fprintf(stderr, "Started capture\r\n");
  char *buffer = (char *)malloc(8192);
  
  // char *ptr = buffer;
  int size = 0;
  
  while(capture->thread_started) {
    int r = snd_pcm_readi(capture->handle, buffer + size, 1024);
    size += r*2*capture->channels;
    if(size < capture->frame_size) {
      continue;
    }
    
    ErlNifEnv* env = enif_alloc_env();
    ErlNifBinary frame;
    
    enif_alloc_binary(capture->frame_size, &frame);
    memmove(frame.data, buffer, frame.size);
    size -= frame.size;
    memmove(buffer, buffer + frame.size, size);
    
    ErlNifUInt64 dts = (uint64_t)capture->counter*1024ULL*1000 / capture->sample_rate;
    
    // fprintf(stderr, "A: %d -> %d\r\n", capture->counter, dts);
    
    if(capture->last_dts > dts) {
      fprintf(stderr, "Achtung! ALSA audio jump: %u, %u, %u\r\n", (unsigned)capture->counter, (unsigned)capture->last_dts, (unsigned)dts);
    }
    capture->last_dts = dts;
    enif_send(NULL, &capture->owner_pid, env, 
      enif_make_tuple4(env,
        enif_make_atom(env, "alsa"),
        enif_make_resource(env, capture),
        enif_make_uint64(env, dts),
        enif_make_binary(env, &frame)
      )
    );
    
    enif_release_binary(&frame);
    
    enif_free_env(env);
    capture->counter++;
  }
  fprintf(stderr, "Capture thread stopping\r\n");
  // enif_release_resource(capture);
  snd_pcm_close(capture->handle);
  return 0;
}
Ejemplo n.º 5
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;
	snd_pcm_uframes_t xfer_align;
	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);
	}
	err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
	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);
	err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);
	if (err < 0) {
		error(_("Unable to obtain xfer align\n"));
		exit(EXIT_FAILURE);
	}
	if (sleep_min)
		xfer_align = 1;
	err = snd_pcm_sw_params_set_sleep_min(handle, swparams,
					      sleep_min);
	assert(err >= 0);
	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 / xfer_align) * xfer_align;
	start_threshold = n;
	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);
	stop_threshold = buffer_size;
	err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
	assert(err >= 0);

	err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);
	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);
	}

	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);
}
Ejemplo n.º 6
0
static int aplaypop_open(void)
{
    int err;
    snd_pcm_t *handle;

    if (pcm_handle)
        return 0;

    snd_pcm_info_t *info;
    snd_pcm_info_alloca(&info);

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

    err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0);
    if (err != 0) {
        fprintf(stderr, "snd_pcm_open(): %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }
    err = snd_pcm_nonblock(handle, 0);
    if (err != 0) {
        fprintf(stderr, "snd_pcm_nonblock(): %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }
    err = snd_pcm_info(handle, info);
    if (err != 0) {
        fprintf(stderr, "snd_pcm_info(): %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }

    // DOESN'T WORK!
    err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE,
        SND_PCM_ACCESS_RW_INTERLEAVED, CHANNELS, RATE, 1, 50000);
    if (err != 0) {
        fprintf(stderr, "snd_pcm_set_params(): %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }

    // RIGHT WAY:
    snd_pcm_hw_params_t *hwparams;
    snd_pcm_sw_params_t *swparams;

    snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
    unsigned int channels = CHANNELS;
    unsigned int rate = RATE;

    snd_pcm_hw_params_alloca(&hwparams);
    snd_pcm_sw_params_alloca(&swparams);

    err = snd_pcm_hw_params_any(handle, hwparams);
    if (err != 0) {
        fprintf(stderr, "Broken configuration for this PCM: %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }
    err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err != 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_access(): %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }
    err = snd_pcm_hw_params_set_format(handle, hwparams, format);
    if (err != 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_format(): %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }
    err = snd_pcm_hw_params_set_channels(handle, hwparams, channels);
    if (err != 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_channels(): %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }
    err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, 0);
    if (err != 0) {
        fprintf(stderr, "snd_pcm_hw_params_set_rate_near(): %s\n", snd_strerror(err));
        exit(EXIT_FAILURE);
    }
/*
    unsigned buffer_time = 0;
    snd_pcm_uframes_t buffer_frames = 0;

    if (buffer_time == 0 && buffer_frames == 0) {
        err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0);
        assert(err == 0);
        if (buffer_time > 500000)
            buffer_time = 500000;
    }

    unsigned period_time = 0;
    snd_pcm_uframes_t period_frames = 0;

    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, hwparams, &period_time, 0);
    else
        err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_frames, 0);
    assert(err == 0);

    if (buffer_time > 0)
        err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
    else
        err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_frames);
    assert(err == 0);

    int monotonic = snd_pcm_hw_params_is_monotonic(hwparams);
    int can_pause = snd_pcm_hw_params_can_pause(hwparams);
*/
    err = snd_pcm_hw_params(handle, hwparams);
    if (err != 0) {
        fprintf(stderr, "snd_pcm_hw_params(): %s\n", snd_strerror(err));
        snd_pcm_hw_params_dump(hwparams, log);
        exit(EXIT_FAILURE);
    }
    snd_pcm_uframes_t chunk_size = 0;
    snd_pcm_hw_params_get_period_size(hwparams, &chunk_size, 0);
    snd_pcm_uframes_t buffer_size;
    snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size);
    if (chunk_size == buffer_size) {
        fprintf(stderr, "Can't use period equal to buffer size (%lu == %lu)",
              chunk_size, buffer_size);
        exit(EXIT_FAILURE);
    }
    snd_pcm_sw_params_current(handle, swparams);

    err = snd_pcm_sw_params_set_avail_min(handle, swparams, chunk_size);
    assert(err == 0);

    /* round up to closest transfer boundary */
    int start_delay = 0;
    snd_pcm_uframes_t start_threshold;
    if (start_delay <= 0)
        start_threshold = buffer_size + (double) rate * start_delay / 1000000;
    else
        start_threshold = (double) rate * start_delay / 1000000;
    start_threshold = start_threshold < 1 ? 1 : start_threshold > buffer_size ? buffer_size : start_threshold;
    err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
    assert(err == 0);

    int stop_delay = 0;
    snd_pcm_uframes_t stop_threshold;
    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);

    err = snd_pcm_sw_params(handle, swparams);
    if (err != 0) {
        fprintf(stderr, "snd_pcm_sw_params(): %s\n", snd_strerror(err));
        snd_pcm_sw_params_dump(swparams, log);
        exit(EXIT_FAILURE);
    }
    // END OF THE RIGHT WAY

//  snd_pcm_dump(handle, log);

    size_t bits_per_sample = snd_pcm_format_physical_width(format);
    size_t bits_per_frame = bits_per_sample * channels;
    size_t chunk_bytes = chunk_size * bits_per_frame / 8;
    //audiobuf = realloc(audiobuf, chunk_bytes);

    fprintf(stderr, "%s: %s, Rate %d Hz, Channels=%u\n",
        snd_pcm_format_name(format), snd_pcm_format_description(format),
        rate, channels);
    fprintf(stderr, "  bits_per_sample=%u, bits_per_frame=%u, chunk_bytes=%u\n",
        bits_per_sample, bits_per_frame, chunk_bytes);

    frame_bytes = bits_per_frame / 8;
    pcm_handle = handle;
    return 0;
}
Ejemplo n.º 7
0
int
ga_alsa_set_param(struct Xcap_alsa_param *param) {
	snd_pcm_hw_params_t *hwparams = NULL;
	snd_pcm_sw_params_t *swparams = NULL;
	size_t bits_per_sample;
	unsigned int rate;
	unsigned int buffer_time = 500000;	// in the unit of microsecond
	unsigned int period_time = 125000;	// = buffer_time/4;
	int monotonic = 0;
	snd_pcm_uframes_t start_threshold, stop_threshold;
	int err;
	//
	snd_pcm_hw_params_alloca(&hwparams);
	snd_pcm_sw_params_alloca(&swparams);
	if((err = snd_pcm_hw_params_any(param->handle, hwparams)) < 0) {
		ga_error("ALSA: set_param - no configurations available\n");
		return -1;
	}
	if((err = snd_pcm_hw_params_set_access(param->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
		ga_error("ALSA: set_param - access type (interleaved) not available\n");
		return -1;
	}
	if((err = snd_pcm_hw_params_set_format(param->handle, hwparams, param->format)) < 0) {
		ga_error("ALSA: set_param - unsupported sample format.\n");
		return -1;
	}
	if((err = snd_pcm_hw_params_set_channels(param->handle, hwparams, param->channels)) < 0) {
		ga_error("ALSA: set_param - channles count not available\n");
		return -1;
	}
	rate = param->samplerate;
	if((err = snd_pcm_hw_params_set_rate_near(param->handle, hwparams, &rate, 0)) < 0) {
		ga_error("ALSA: set_param - set rate failed.\n");
		return -1;
	}
	if((double)param->samplerate*1.05 < rate || (double)param->samplerate*0.95 > rate) {
		ga_error("ALSA: set_param/warning - inaccurate rate (req=%iHz, got=%iHz)\n", param->samplerate, rate);
	}
	//
	period_time = buffer_time/4;
	if((err = snd_pcm_hw_params_set_period_time_near(param->handle, hwparams, &period_time, 0)) < 0) {
		ga_error("ALSA: set_param - set period time failed.\n");
		return -1;
	}
	if((err = snd_pcm_hw_params_set_buffer_time_near(param->handle, hwparams, &buffer_time, 0)) < 0) {
		ga_error("ALSA: set_param - set buffer time failed.\n");
		return -1;
	}
	//
	monotonic = snd_pcm_hw_params_is_monotonic(hwparams);
	if((err = snd_pcm_hw_params(param->handle, hwparams)) < 0) {
		ga_error("ALSA: set_param - unable to install hw params:");
		snd_pcm_hw_params_dump(hwparams, sndlog);
		return -1;
	}
	snd_pcm_hw_params_get_period_size(hwparams, &param->chunk_size, 0);
	snd_pcm_hw_params_get_buffer_size(hwparams, &param->buffer_size);
	if(param->chunk_size == param->buffer_size) {
		ga_error("ALSA: set_param - cannot use period equal to buffer size (%lu==%lu)\n",
			param->chunk_size, param->buffer_size);
		return -1;
	}
	//
	snd_pcm_sw_params_current(param->handle, swparams);
	err = snd_pcm_sw_params_set_avail_min(param->handle, swparams, param->chunk_size);
	// start_delay = 1 for capture
	start_threshold = (double) param->samplerate * /*start_delay=*/ 1 / 1000000;
	if(start_threshold < 1)				start_threshold = 1;
	if(start_threshold > param->buffer_size)	start_threshold = param->buffer_size;
	if((err = snd_pcm_sw_params_set_start_threshold(param->handle, swparams, start_threshold)) < 0) {
		ga_error("ALSA: set_param - set start threshold failed.\n");
		return -1;
	}
	// stop_delay = 0
	stop_threshold = param->buffer_size;
	if((err = snd_pcm_sw_params_set_stop_threshold(param->handle, swparams, stop_threshold)) < 0) {
		ga_error("ALSA: set_param - set stop threshold failed.\n");
		return -1;
	}
	//
	if(snd_pcm_sw_params(param->handle, swparams) < 0) {
		ga_error("ALSA: set_param - unable to install sw params:");
		snd_pcm_sw_params_dump(swparams, sndlog);
		return -1;
	}

	bits_per_sample = snd_pcm_format_physical_width(param->format);
	if(param->bits_per_sample != bits_per_sample) {
		ga_error("ALSA: set_param - BPS/HW configuration mismatched %d != %d)\n",
			param->bits_per_sample, bits_per_sample);
	}
	param->bits_per_frame = param->bits_per_sample * param->channels;
	param->chunk_bytes = param->chunk_size * param->bits_per_frame / 8;

	return 0;
}
Ejemplo n.º 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);
	}
	if (mmap_flag) {
		snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof());
		snd_pcm_access_mask_none(mask);
		snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
		snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
		snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
		err = snd_pcm_hw_params_set_access_mask(handle, params, mask);
	} 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);
	if (err < 0) {
		error("Setting sw params failed\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;
	}

	/* show mmap buffer arragment */
	if (mmap_flag && verbose) {
		const snd_pcm_channel_area_t *areas;
		snd_pcm_uframes_t offset;
		int i;
		err = snd_pcm_mmap_begin(handle, &areas, &offset, &chunk_size);
		if (err < 0) {
			error("snd_pcm_mmap_begin problem: %s", snd_strerror(err));
			exit(EXIT_FAILURE);
		}
		for (i = 0; i < hwparams.channels; i++)
			fprintf(stderr, "mmap_area[%i] = %p,%u,%u (%u)\n", i, areas[i].addr, areas[i].first, areas[i].step, snd_pcm_format_physical_width(hwparams.format));
		/* not required, but for sure */
		snd_pcm_mmap_commit(handle, offset, 0);
	}

	buffer_frames = buffer_size;	/* for position test */
}
Ejemplo n.º 9
0
    bool setParameters (unsigned int sampleRate, int numChannels, int bufferSize)
    {
        if (handle == nullptr)
            return false;

        JUCE_ALSA_LOG ("ALSADevice::setParameters(" << deviceID << ", "
                         << (int) sampleRate << ", " << numChannels << ", " << bufferSize << ")");

        snd_pcm_hw_params_t* hwParams;
        snd_pcm_hw_params_alloca (&hwParams);

        if (snd_pcm_hw_params_any (handle, hwParams) < 0)
        {
            // this is the error message that aplay returns when an error happens here,
            // it is a bit more explicit that "Invalid parameter"
            error = "Broken configuration for this PCM: no configurations available";
            return false;
        }

        if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) >= 0) // works better for plughw..
            isInterleaved = true;
        else if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_NONINTERLEAVED) >= 0)
            isInterleaved = false;
        else
        {
            jassertfalse;
            return false;
        }

        enum { isFloatBit = 1 << 16, isLittleEndianBit = 1 << 17, onlyUseLower24Bits = 1 << 18 };

        const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE,   32 | isFloatBit | isLittleEndianBit,
                                     SND_PCM_FORMAT_FLOAT_BE,   32 | isFloatBit,
                                     SND_PCM_FORMAT_S32_LE,     32 | isLittleEndianBit,
                                     SND_PCM_FORMAT_S32_BE,     32,
                                     SND_PCM_FORMAT_S24_3LE,    24 | isLittleEndianBit,
                                     SND_PCM_FORMAT_S24_3BE,    24,
                                     SND_PCM_FORMAT_S24_LE,     32 | isLittleEndianBit | onlyUseLower24Bits,
                                     SND_PCM_FORMAT_S16_LE,     16 | isLittleEndianBit,
                                     SND_PCM_FORMAT_S16_BE,     16 };
        bitDepth = 0;

        for (int i = 0; i < numElementsInArray (formatsToTry); i += 2)
        {
            if (snd_pcm_hw_params_set_format (handle, hwParams, (_snd_pcm_format) formatsToTry [i]) >= 0)
            {
                const int type = formatsToTry [i + 1];
                bitDepth = type & 255;

                converter.reset (createConverter (isInput, bitDepth,
                                                  (type & isFloatBit) != 0,
                                                  (type & isLittleEndianBit) != 0,
                                                  (type & onlyUseLower24Bits) != 0,
                                                  numChannels,
                                                  isInterleaved));
                break;
            }
        }

        if (bitDepth == 0)
        {
            error = "device doesn't support a compatible PCM format";
            JUCE_ALSA_LOG ("Error: " + error);
            return false;
        }

        int dir = 0;
        unsigned int periods = 4;
        snd_pcm_uframes_t samplesPerPeriod = (snd_pcm_uframes_t) bufferSize;

        if (JUCE_ALSA_FAILED (snd_pcm_hw_params_set_rate_near (handle, hwParams, &sampleRate, 0))
            || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_channels (handle, hwParams, (unsigned int ) numChannels))
            || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_periods_near (handle, hwParams, &periods, &dir))
            || JUCE_ALSA_FAILED (snd_pcm_hw_params_set_period_size_near (handle, hwParams, &samplesPerPeriod, &dir))
            || JUCE_ALSA_FAILED (snd_pcm_hw_params (handle, hwParams)))
        {
            return false;
        }

        snd_pcm_uframes_t frames = 0;

        if (JUCE_ALSA_FAILED (snd_pcm_hw_params_get_period_size (hwParams, &frames, &dir))
             || JUCE_ALSA_FAILED (snd_pcm_hw_params_get_periods (hwParams, &periods, &dir)))
            latency = 0;
        else
            latency = (int) frames * ((int) periods - 1); // (this is the method JACK uses to guess the latency..)

        JUCE_ALSA_LOG ("frames: " << (int) frames << ", periods: " << (int) periods
                          << ", samplesPerPeriod: " << (int) samplesPerPeriod);

        snd_pcm_sw_params_t* swParams;
        snd_pcm_sw_params_alloca (&swParams);
        snd_pcm_uframes_t boundary;

        if (JUCE_ALSA_FAILED (snd_pcm_sw_params_current (handle, swParams))
            || JUCE_ALSA_FAILED (snd_pcm_sw_params_get_boundary (swParams, &boundary))
            || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_silence_threshold (handle, swParams, 0))
            || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_silence_size (handle, swParams, boundary))
            || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_start_threshold (handle, swParams, samplesPerPeriod))
            || JUCE_ALSA_FAILED (snd_pcm_sw_params_set_stop_threshold (handle, swParams, boundary))
            || JUCE_ALSA_FAILED (snd_pcm_sw_params (handle, swParams)))
        {
            return false;
        }

       #if JUCE_ALSA_LOGGING
        // enable this to dump the config of the devices that get opened
        snd_output_t* out;
        snd_output_stdio_attach (&out, stderr, 0);
        snd_pcm_hw_params_dump (hwParams, out);
        snd_pcm_sw_params_dump (swParams, out);
       #endif

        numChannelsRunning = numChannels;

        return true;
    }
Ejemplo n.º 10
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;
}
Ejemplo n.º 11
0
bool
AlsaSource::SetupHW ()
{
	bool result = false;
	bool rw_available = false;
	bool mmap_available = false;
#if DEBUG
	bool debug = debug_flags & RUNTIME_DEBUG_AUDIO;
#else
	bool debug = false;
#endif
	
	snd_pcm_hw_params_t *params = NULL;
	snd_output_t *output = NULL;
	guint32 buffer_time = 100000; // request 0.1 seconds of buffer time.
	int err = 0;
	int dir = 0;
	unsigned int rate = GetSampleRate ();
	unsigned int actual_rate = rate;
	guint32 channels = GetChannels ();

	if (debug) {
		err = snd_output_stdio_attach (&output, stdout, 0);
		if (err < 0)
			LOG_AUDIO ("AlsaSource::SetupHW (): Could not create alsa output: %s\n", snd_strerror (err));
	}

	err = snd_pcm_hw_params_malloc (&params);
	if (err < 0) {
		LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (malloc): %s\n", snd_strerror (err));
		return false;
	}

	// choose all parameters
	err = snd_pcm_hw_params_any (pcm, params);
	if (err < 0) {
		LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (no configurations available): %s\n", snd_strerror (err));
		goto cleanup;
	}
	
	if (debug && output != NULL) {
		LOG_AUDIO ("AlsaSource::SetupHW (): hw configurations:\n");
		snd_pcm_hw_params_dump (params, output);
	}
	
	// enable software resampling
	err = snd_pcm_hw_params_set_rate_resample (pcm, params, 1);
	if (err < 0) {
		LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (could not enable resampling): %s\n", snd_strerror (err));
		goto cleanup;
	}
	
	// test for available transfer modes
	if (!(moonlight_flags & RUNTIME_INIT_AUDIO_ALSA_MMAP)) {
		err = snd_pcm_hw_params_test_access (pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED);
		if (err < 0) {
			LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup: RW access mode not supported (%s).\n", snd_strerror (err));			
		} else {
			rw_available = true;
		}
	}
	if (!(moonlight_flags & RUNTIME_INIT_AUDIO_ALSA_RW)) {
		err = snd_pcm_hw_params_test_access (pcm, params, SND_PCM_ACCESS_MMAP_INTERLEAVED);
		if (err < 0) {
			LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup: MMAP access mode not supported (%s).\n", snd_strerror (err));
		} else {
			mmap_available = true;
		}
	}
	if (mmap_available) {
		mmap = true;
	} else if (rw_available) {
		mmap = false;
	} else {
		LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed, no available access mode\n");
		goto cleanup;
	}

	LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup: using %s access mode.\n", mmap ? "MMAP" : "RW");

	// set transfer mode (mmap or rw in our case)
	err = snd_pcm_hw_params_set_access (pcm, params, mmap ? SND_PCM_ACCESS_MMAP_INTERLEAVED : SND_PCM_ACCESS_RW_INTERLEAVED);
	if (err < 0) {
		LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (access type not available for playback): %s\n", snd_strerror (err));
		goto cleanup;
	}

	// set audio format
	switch (GetInputBytesPerSample ()) {
	case 1: // 8 bit audio
		err = snd_pcm_hw_params_set_format (pcm, params, SND_PCM_FORMAT_S16);
		SetOutputBytesPerSample (2);
		break;
	case 2: // 16 bit audio
		err = snd_pcm_hw_params_set_format (pcm, params, SND_PCM_FORMAT_S16);
		SetOutputBytesPerSample (2);
		break;
	case 3: // 24 bit audio
		// write as 32 bit audio, this is a lot easier to write to than 24 bit.
		err = snd_pcm_hw_params_set_format (pcm, params, SND_PCM_FORMAT_S32);
		SetOutputBytesPerSample (4);
		break;
	default:
		LOG_AUDIO ("AlsaSource::SetupHW (): Invalid input bytes per sample, expected 1, 2 or 3, got %i\n", GetInputBytesPerSample ());
		goto cleanup;
	}
	
	if (err < 0) {
		LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (sample format not available for playback): %s\n", snd_strerror (err));
		goto cleanup;
	}
	
	// set channel count
	err = snd_pcm_hw_params_set_channels (pcm, params, channels);
	if (err < 0) {
		LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (channels count %i not available for playback): %s\n", channels, snd_strerror (err));
		goto cleanup;
	}
	
	// set sample rate
	err = snd_pcm_hw_params_set_rate_near (pcm, params, &actual_rate, 0);
	if (err < 0) {
		LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (sample rate %i Hz not available for playback): %s\n", rate, snd_strerror (err));
		goto cleanup;
	} else if (actual_rate != rate) {
		LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (sample rate %i Hz not available for playback, only got %i Hz).\n", rate, actual_rate);
		goto cleanup;
	}
	
	// set the buffer time
	err = snd_pcm_hw_params_set_buffer_time_near (pcm, params, &buffer_time, &dir);
	if (err < 0) {
		LOG_AUDIO ("AudioNode::SetupHW (): Audio HW setup failed (unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror (err));
		goto cleanup;
	}

	// write the parameters to device
	err = snd_pcm_hw_params (pcm, params);
	if (err < 0) {
		LOG_AUDIO ("AlsaSource::SetupHW (): Audio HW setup failed (unable to set hw params for playback: %s)\n", snd_strerror (err));
		if (debug && output != NULL) {
			LOG_AUDIO ("AlsaSource::SetupHW (): current hw configurations:\n");
			snd_pcm_hw_params_dump (params, output);
		}
		goto cleanup;
	}
	
	if (debug) {
		LOG_AUDIO ("AlsaSource::SetupHW (): hardware pause support: %s\n", snd_pcm_hw_params_can_pause (params) == 0 ? "no" : "yes"); 
		LOG_AUDIO ("AlsaSource::SetupHW (): succeeded\n");
		if (output != NULL) 
			snd_pcm_hw_params_dump (params, output);
	}

	result = true;
	
cleanup:
	snd_pcm_hw_params_free (params);
	
	return result;
}
Ejemplo n.º 12
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;
}
Ejemplo n.º 13
0
static int
set_params(AudioDevice *ad, AudioFormat *format_p, int *ch_p, unsigned int *rate_p)
{
  ALSA_data *alsa = (ALSA_data *)ad->private_data;
  int r, err;
  snd_pcm_format_t f;
  AudioFormat format = *format_p;
  snd_pcm_hw_params_t *hwparams;
  snd_pcm_sw_params_t *swparams;
  int ch = *ch_p;
  unsigned int rate = *rate_p;
  unsigned int buffer, period;

  snd_pcm_hw_params_alloca(&hwparams);
  snd_pcm_sw_params_alloca(&swparams);

  ad->format = _AUDIO_FORMAT_UNSET;
  *format_p = _AUDIO_FORMAT_UNSET;
  *ch_p = 0;
  *rate_p = 0;

  /* format part */
  switch (format) {
  case _AUDIO_FORMAT_MU_LAW:
    f = SND_PCM_FORMAT_MU_LAW;
    break;
  case _AUDIO_FORMAT_A_LAW:
    f = SND_PCM_FORMAT_A_LAW;
    break;
  case _AUDIO_FORMAT_ADPCM:
    f = SND_PCM_FORMAT_IMA_ADPCM;
    break;
  case _AUDIO_FORMAT_U8:
    f = SND_PCM_FORMAT_U8;
    break;
  case _AUDIO_FORMAT_S8:
    f = SND_PCM_FORMAT_S8;
    break;
  case _AUDIO_FORMAT_U16_LE:
    f = SND_PCM_FORMAT_U16_LE;
    break;
  case _AUDIO_FORMAT_U16_BE:
    f = SND_PCM_FORMAT_U16_BE;
    break;
  case _AUDIO_FORMAT_S16_LE:
    f = SND_PCM_FORMAT_S16_LE;
    break;
  case _AUDIO_FORMAT_S16_BE:
    f = SND_PCM_FORMAT_S16_BE;
    break;
#if 0
  case _AUDIO_FORMAT_S32_LE:
    f = SND_PCM_FORMAT_U32_LE;
    break;
  case _AUDIO_FORMAT_S32_BE:
    f = SND_PCM_FORMAT_S32_BE;
    break;
#endif
  default:
    show_message_fnc("format %d is invalid.\n", format);
    return 0;
  }

  if ((err = snd_pcm_hw_params_any(alsa->fd, hwparams)) < 0) {
    show_message_fnc("snd_pcm_hw_params_any() failed.\n");
    return 0;
  }

  if ((err = snd_pcm_hw_params_set_access(alsa->fd, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_access() failed.\n");
    return 0;
  }

  if ((err = snd_pcm_hw_params_set_format(alsa->fd, hwparams, f)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_format() failed.\n");
    return 0;
  }
  ad->format = format;
  *format_p = format;

  /* channel part */
  if ((err = snd_pcm_hw_params_set_channels(alsa->fd, hwparams, ch)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_channels() failed.\n");
    return 0;
  }
  *ch_p = ch;

  /* rate part */
  if ((err = snd_pcm_hw_params_set_rate_near(alsa->fd, hwparams, &rate, 0)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_rate_near() failed.\n");
    return 0;
  }
  *rate_p = rate;

  /* buffer & period */
  buffer = 500000;
  period = 500000 / 4;
  if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa->fd, hwparams, &buffer, 0)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_buffer_near() failed.\n");
    return 0;
  }
  r = snd_pcm_hw_params_get_buffer_size(hwparams, &alsa->buffer_size);
  if ((err = snd_pcm_hw_params_set_period_time_near(alsa->fd, hwparams, &period, 0)) < 0) {
    show_message_fnc("snd_pcm_hw_params_set_period_near() failed.\n");
    return 0;
  }
  r = snd_pcm_hw_params_get_period_size(hwparams, &alsa->period_size, 0);

  if ((err = snd_pcm_hw_params(alsa->fd, hwparams)) < 0) {
    perror("snd_pcm_hw_params");
    err_message_fnc("snd_pcm_hw_params() failed.\n");
    snd_pcm_hw_params_dump(hwparams, alsa->log);
    return 0;
  }

  r = snd_pcm_hw_params_get_channels(hwparams, &ad->channels);
  r = snd_pcm_hw_params_get_rate(hwparams, &ad->speed, 0);
  r = r; // dummy

#ifdef DEBUG
  {
    snd_pcm_format_t form;

    debug_message_fnc("format ");
    r = snd_pcm_hw_params_get_format(hwparams, &form);
    switch (form) {
    case SND_PCM_FORMAT_MU_LAW:    debug_message("MU_LAW "); break;
    case SND_PCM_FORMAT_A_LAW:     debug_message("A_LAW "); break;
    case SND_PCM_FORMAT_IMA_ADPCM: debug_message("ADPCM "); break;
    case SND_PCM_FORMAT_U8:        debug_message("U8 "); break;
    case SND_PCM_FORMAT_S8:        debug_message("S8 "); break;
    case SND_PCM_FORMAT_U16_LE:    debug_message("U16LE "); break;
    case SND_PCM_FORMAT_U16_BE:    debug_message("U16BE "); break;
    case SND_PCM_FORMAT_S16_LE:    debug_message("S16LE "); break;
    case SND_PCM_FORMAT_S16_BE:    debug_message("S16BE "); break;
#if 0
    case SND_PCM_FORMAT_U32_LE:    debug_message("U32LE "); break;
    case SND_PCM_FORMAT_S32_BE:    debug_message("S32BE "); break;
#endif
    default:                       debug_message("UNKNOWN "); break;
    }

    debug_message("%d ch %d Hz buffer %ld period %ld OK\n", ad->channels, ad->speed, alsa->buffer_size, alsa->period_size);
  }
#endif

  /* sw_params */
  if ((err = snd_pcm_sw_params_current(alsa->fd, swparams)) < 0) {
    show_message_fnc("snd_pcm_sw_params_any() failed.\n");
    return 0;
  }
  if ((err = snd_pcm_sw_params(alsa->fd, swparams)) < 0) {
    show_message_fnc("snd_pcm_sw_params() failed.\n");
    return 0;
  }

  debug_message_fnc("1 sample -> %ld bytes\n", snd_pcm_samples_to_bytes(alsa->fd, 1));

  return 1;
}
Ejemplo n.º 14
0
    bool setParameters (unsigned int sampleRate, int numChannels, int bufferSize)
    {
        if (handle == 0)
            return false;

        snd_pcm_hw_params_t* hwParams;
        snd_pcm_hw_params_alloca (&hwParams);

        if (failed (snd_pcm_hw_params_any (handle, hwParams)))
            return false;

        if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_NONINTERLEAVED) >= 0)
            isInterleaved = false;
        else if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) >= 0)
            isInterleaved = true;
        else
        {
            jassertfalse;
            return false;
        }

        enum { isFloatBit = 1 << 16, isLittleEndianBit = 1 << 17 };

        const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE,   32 | isFloatBit | isLittleEndianBit,
                                     SND_PCM_FORMAT_FLOAT_BE,   32 | isFloatBit,
                                     SND_PCM_FORMAT_S32_LE,     32 | isLittleEndianBit,
                                     SND_PCM_FORMAT_S32_BE,     32,
                                     SND_PCM_FORMAT_S24_3LE,    24 | isLittleEndianBit,
                                     SND_PCM_FORMAT_S24_3BE,    24,
                                     SND_PCM_FORMAT_S16_LE,     16 | isLittleEndianBit,
                                     SND_PCM_FORMAT_S16_BE,     16 };
        bitDepth = 0;

        for (int i = 0; i < numElementsInArray (formatsToTry); i += 2)
        {
            if (snd_pcm_hw_params_set_format (handle, hwParams, (_snd_pcm_format) formatsToTry [i]) >= 0)
            {
                bitDepth = formatsToTry [i + 1] & 255;
                const bool isFloat = (formatsToTry [i + 1] & isFloatBit) != 0;
                const bool isLittleEndian = (formatsToTry [i + 1] & isLittleEndianBit) != 0;
                converter = createConverter (isInput, bitDepth, isFloat, isLittleEndian, numChannels);
                break;
            }
        }

        if (bitDepth == 0)
        {
            error = "device doesn't support a compatible PCM format";
            DBG ("ALSA error: " + error + "\n");
            return false;
        }

        int dir = 0;
        unsigned int periods = 4;
        snd_pcm_uframes_t samplesPerPeriod = bufferSize;

        if (failed (snd_pcm_hw_params_set_rate_near (handle, hwParams, &sampleRate, 0))
            || failed (snd_pcm_hw_params_set_channels (handle, hwParams, numChannels))
            || failed (snd_pcm_hw_params_set_periods_near (handle, hwParams, &periods, &dir))
            || failed (snd_pcm_hw_params_set_period_size_near (handle, hwParams, &samplesPerPeriod, &dir))
            || failed (snd_pcm_hw_params (handle, hwParams)))
        {
            return false;
        }

        snd_pcm_uframes_t frames = 0;

        if (failed (snd_pcm_hw_params_get_period_size (hwParams, &frames, &dir))
             || failed (snd_pcm_hw_params_get_periods (hwParams, &periods, &dir)))
            latency = 0;
        else
            latency = frames * (periods - 1); // (this is the method JACK uses to guess the latency..)

        snd_pcm_sw_params_t* swParams;
        snd_pcm_sw_params_alloca (&swParams);
        snd_pcm_uframes_t boundary;

        if (failed (snd_pcm_sw_params_current (handle, swParams))
            || failed (snd_pcm_sw_params_get_boundary (swParams, &boundary))
            || failed (snd_pcm_sw_params_set_silence_threshold (handle, swParams, 0))
            || failed (snd_pcm_sw_params_set_silence_size (handle, swParams, boundary))
            || failed (snd_pcm_sw_params_set_start_threshold (handle, swParams, samplesPerPeriod))
            || failed (snd_pcm_sw_params_set_stop_threshold (handle, swParams, boundary))
            || failed (snd_pcm_sw_params (handle, swParams)))
        {
            return false;
        }

      #if 0
        // enable this to dump the config of the devices that get opened
        snd_output_t* out;
        snd_output_stdio_attach (&out, stderr, 0);
        snd_pcm_hw_params_dump (hwParams, out);
        snd_pcm_sw_params_dump (swParams, out);
      #endif

        numChannelsRunning = numChannels;

        return true;
    }
Ejemplo n.º 15
0
AudioStream* AlsaBackend::OpenStream(StreamDirection dir, DeviceInfo* device, StreamSpec& spec, SOUNDCARD_CALLBACK callback, void* userdata)
{
    if (!device->probed)
        if (!ProbeDevice(device, spec))
            return NULL;

    if (!device->mixer)
    {
        Log("Device was probed but no mixer set, trying to enable now.");
        device->mixer = new AlsaVolumeControl;
        static_cast<AlsaVolumeControl*>(device->mixer)->ProbeMixer(device);
    }

    snd_pcm_stream_t stream;
    if (dir == INPUT)
        stream = SND_PCM_STREAM_CAPTURE;
    else if (dir >= OUTPUT)
        stream = SND_PCM_STREAM_PLAYBACK;
    else
    {
        return NULL;
    }

    AudioStream *audioStream = new AudioStream;
    MutexLock lock(audioStream->mutex);
    Log("AlsaBackend.open_stream_lock");

    //int result;
    snd_pcm_t *phandle = 0;
    int openMode = SND_PCM_ASYNC;
    snd_output_t *out;

    _EE_CALL(snd_pcm_open(&phandle, device->guid, stream, openMode), false, phandle, "pcm device %s won't open for %s", device->displayName, dir==INPUT?"input":"output");

    // Fill the parameter structure.
    AlsaHardwareParams alsa_hw_params(phandle);

#define DUMP_PARAMS(out, title, func)                \
    if (!snd_output_buffer_open(&out))               \
    {                                                \
        char* str;                                   \
        Log(title);                                  \
        func;                                        \
        snd_output_putc(out, '\0');                  \
        if (snd_output_buffer_string(out, &str) > 0) \
            Log("%s",str);                           \
        snd_output_close(out);                       \
    }

    DUMP_PARAMS(out, "AlsaBackend: dump hardware params just after device open:", snd_pcm_hw_params_dump(alsa_hw_params, out));

    // Set up interleaving
    audioStream->userInterleaved = true;
    audioStream->deviceInterleaved = true;

    bool use_mmap = false;
    alsa_hw_params.set_params(&spec, &use_mmap);

    audioStream->deviceFormat = audioStream->userFormat = spec.format;
    audioStream->deviceChannels = audioStream->userChannels = spec.channels;

    DUMP_PARAMS(out, "AlsaBackend: dump hardware params after installation:", snd_pcm_hw_params_dump(alsa_hw_params, out));

    AlsaSoftwareParams sw_params(phandle);
    sw_params.set_params(spec.fragmentFrames, true);

    DUMP_PARAMS(out, "AlsaBackend: dump software params after installation:", snd_pcm_sw_params_dump(sw_params, out));

    // Allocate the ApiHandle if necessary and then save.
    AlsaHandle *apiInfo = 0;
    if (audioStream->apiHandle == 0) {
        apiInfo = new AlsaHandle;
        if (!apiInfo) 
        {
            Log("error allocating AlsaHandle memory");
            delete audioStream;
            return NULL;

        }
        audioStream->apiHandle = (void *) apiInfo;
        apiInfo->handle = 0;
    }
    else {
        apiInfo = (AlsaHandle *) audioStream->apiHandle;
    }
    apiInfo->handle = phandle;
    apiInfo->xrun = false;
    apiInfo->type = device->type;

    audioStream->spec = spec;
    audioStream->running = 0;
    audioStream->dir = dir;
    audioStream->mixer = device->mixer;

    // Setup callback thread.
    audioStream->callback.object = this;
    audioStream->callback.stream = audioStream;
    audioStream->callback.callback = callback;
    audioStream->callback.userdata = userdata;
    audioStream->callback.apiInfo = apiInfo;

    audioStream->callback.isRunning = 1;

    // Allocate necessary internal buffer.
    audioStream->buffer = new PhantomRingbuffer(spec.FrameBytes(), spec.bufferFrames, spec.fragmentFrames);
    if (audioStream->buffer == NULL)
    {
        Log("error allocating ringbuffer memory");
        if (apiInfo) 
        {
            if (apiInfo->handle)
                snd_pcm_close(apiInfo->handle);
            delete apiInfo;
            apiInfo = NULL;
            audioStream->apiHandle = 0;
        }

        delete audioStream;
        return NULL;
    }

    p_alsathread[audioStream] = new AlsaThread(&audioStream->callback, dir == INPUT ? "alsa_capture_thread" : "alsa_playback_thread");
    pthread_create(&thrd,NULL,&(AlsaThread::run),p_alsathread[audioStream]);
    pthread_detach(thrd);
    Log("Using %0.1f fragments of size %lu bytes (%0.2fms), buffer size is %lu bytes (%0.2fms)",
                (double) (spec.bufferFrames * spec.FrameBytes()) / (double) (spec.fragmentFrames * spec.FrameBytes()),
                (long unsigned) spec.fragmentFrames * spec.FrameBytes(),
                spec.FragmentMs(),
                (long unsigned) spec.bufferFrames * spec.FrameBytes(),
                spec.BufferMs());

    return audioStream;
}