Example #1
0
/* Get the pcm boundary value. */
static int get_boundary(snd_pcm_t *pcm, snd_pcm_uframes_t *boundary)
{
	snd_pcm_sw_params_t *sw_params;
	int rc;

	snd_pcm_sw_params_alloca(&sw_params);

	rc = snd_pcm_sw_params_current(pcm, sw_params);
	if (rc < 0) {
		fprintf(stderr, "sw_params_current: %s\n", snd_strerror(rc));
		return rc;
	}

	rc = snd_pcm_sw_params_get_boundary(sw_params, boundary);
	if (rc < 0) {
		fprintf(stderr, "get_boundary: %s\n", snd_strerror(rc));
		return rc;
	}

	return 0;
}
Example #2
0
bool CAESinkALSA::InitializeSW(AEAudioFormat &format)
{
  snd_pcm_sw_params_t *sw_params;
  snd_pcm_uframes_t boundary;

  snd_pcm_sw_params_alloca(&sw_params);
  memset(sw_params, 0, snd_pcm_sw_params_sizeof());

  snd_pcm_sw_params_current              (m_pcm, sw_params);
  snd_pcm_sw_params_set_start_threshold  (m_pcm, sw_params, INT_MAX);
  snd_pcm_sw_params_set_silence_threshold(m_pcm, sw_params, 0);
  snd_pcm_sw_params_get_boundary         (sw_params, &boundary);
  snd_pcm_sw_params_set_silence_size     (m_pcm, sw_params, boundary);
  snd_pcm_sw_params_set_avail_min        (m_pcm, sw_params, format.m_frames);

  if (snd_pcm_sw_params(m_pcm, sw_params) < 0)
  {
    CLog::Log(LOGERROR, "CAESinkALSA::InitializeSW - Failed to set the parameters");
    return false;
  }

  return true;
}
Example #3
0
bool AudioInputALSA::PrepSwParams(void)
{
    snd_pcm_sw_params_t* swparams;
    snd_pcm_sw_params_alloca(&swparams);
    snd_pcm_uframes_t boundary;
    if (AlsaBad(snd_pcm_sw_params_current(pcm_handle, swparams),
                "failed to get swparams"))
        return false;
    if (AlsaBad(snd_pcm_sw_params_get_boundary(swparams, &boundary),
                "failed to get boundary"))
        return false;
    // explicit start, not auto start
    if (AlsaBad(snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,
                boundary), "failed to set start threshold"))
        return false;
    if (AlsaBad(snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams,
                boundary), "failed to set stop threshold"))
        return false;
    if (AlsaBad(snd_pcm_sw_params(pcm_handle, swparams),
                "failed to set software parameters"))
        return false;

    return true;
}
int main(int argc, char *argv[]) {
    const char *dev;
    int r, cap, count = 0;
    snd_pcm_hw_params_t *hwparams;
    snd_pcm_sw_params_t *swparams;
    snd_pcm_status_t *status;
    snd_pcm_t *pcm;
    unsigned rate = 44100;
    unsigned periods = 2;
    snd_pcm_uframes_t boundary, buffer_size = 44100/10; /* 100s */
    int dir = 1;
    struct timespec start, last_timestamp = { 0, 0 };
    uint64_t start_us, last_us = 0;
    snd_pcm_sframes_t last_avail = 0, last_delay = 0;
    struct pollfd *pollfds;
    int n_pollfd;
    int64_t sample_count = 0;
    struct sched_param sp;

    r = -1;
#ifdef _POSIX_PRIORITY_SCHEDULING
    sp.sched_priority = 5;
    r = pthread_setschedparam(pthread_self(), SCHED_RR, &sp);
#endif
    if (r)
        printf("Could not get RT prio. :(\n");

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

    r = clock_gettime(CLOCK_MONOTONIC, &start);
    assert(r == 0);

    start_us = timespec_us(&start);

    dev = argc > 1 ? argv[1] : "front:AudioPCI";
    cap = argc > 2 ? atoi(argv[2]) : 0;

    if (cap == 0)
      r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_PLAYBACK, 0);
    else
      r = snd_pcm_open(&pcm, dev, SND_PCM_STREAM_CAPTURE, 0);
    assert(r == 0);

    r = snd_pcm_hw_params_any(pcm, hwparams);
    assert(r == 0);

    r = snd_pcm_hw_params_set_rate_resample(pcm, hwparams, 0);
    assert(r == 0);

    r = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
    assert(r == 0);

    r = snd_pcm_hw_params_set_format(pcm, hwparams, SND_PCM_FORMAT_S16_LE);
    assert(r == 0);

    r = snd_pcm_hw_params_set_rate_near(pcm, hwparams, &rate, NULL);
    assert(r == 0);

    r = snd_pcm_hw_params_set_channels(pcm, hwparams, 2);
    assert(r == 0);

    r = snd_pcm_hw_params_set_periods_integer(pcm, hwparams);
    assert(r == 0);

    r = snd_pcm_hw_params_set_periods_near(pcm, hwparams, &periods, &dir);
    assert(r == 0);

    r = snd_pcm_hw_params_set_buffer_size_near(pcm, hwparams, &buffer_size);
    assert(r == 0);

    r = snd_pcm_hw_params(pcm, hwparams);
    assert(r == 0);

    r = snd_pcm_hw_params_current(pcm, hwparams);
    assert(r == 0);

    r = snd_pcm_sw_params_current(pcm, swparams);
    assert(r == 0);

    if (cap == 0)
      r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 1);
    else
      r = snd_pcm_sw_params_set_avail_min(pcm, swparams, 0);
    assert(r == 0);

    r = snd_pcm_sw_params_set_period_event(pcm, swparams, 0);
    assert(r == 0);

    r = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size);
    assert(r == 0);
    r = snd_pcm_sw_params_set_start_threshold(pcm, swparams, buffer_size);
    assert(r == 0);

    r = snd_pcm_sw_params_get_boundary(swparams, &boundary);
    assert(r == 0);
    r = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary);
    assert(r == 0);

    r = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE);
    assert(r == 0);

    r = snd_pcm_sw_params(pcm, swparams);
    assert(r == 0);

    r = snd_pcm_prepare(pcm);
    assert(r == 0);

    r = snd_pcm_sw_params_current(pcm, swparams);
    assert(r == 0);

/*     assert(snd_pcm_hw_params_is_monotonic(hwparams) > 0); */

    n_pollfd = snd_pcm_poll_descriptors_count(pcm);
    assert(n_pollfd > 0);

    pollfds = malloc(sizeof(struct pollfd) * n_pollfd);
    assert(pollfds);

    r = snd_pcm_poll_descriptors(pcm, pollfds, n_pollfd);
    assert(r == n_pollfd);

    printf("Starting. Buffer size is %u frames\n", (unsigned int) buffer_size);

    if (cap) {
      r = snd_pcm_start(pcm);
      assert(r == 0);
    }

    for (;;) {
        snd_pcm_sframes_t avail, delay;
        struct timespec now, timestamp;
        unsigned short revents;
        int handled = 0;
        uint64_t now_us, timestamp_us;
        snd_pcm_state_t state;
        unsigned long long pos;

        r = poll(pollfds, n_pollfd, 0);
        assert(r >= 0);

        r = snd_pcm_poll_descriptors_revents(pcm, pollfds, n_pollfd, &revents);
        assert(r == 0);

        if (cap == 0)
          assert((revents & ~POLLOUT) == 0);
        else
          assert((revents & ~POLLIN) == 0);

        avail = snd_pcm_avail(pcm);
        assert(avail >= 0);

        r = snd_pcm_status(pcm, status);
        assert(r == 0);

        /* This assertion fails from time to time. ALSA seems to be broken */
/*         assert(avail == (snd_pcm_sframes_t) snd_pcm_status_get_avail(status)); */
/*         printf("%lu %lu\n", (unsigned long) avail, (unsigned long) snd_pcm_status_get_avail(status)); */

        snd_pcm_status_get_htstamp(status, &timestamp);
        delay = snd_pcm_status_get_delay(status);
        state = snd_pcm_status_get_state(status);

        r = clock_gettime(CLOCK_MONOTONIC, &now);
        assert(r == 0);

        assert(!revents || avail > 0);

        if ((!cap && avail) || (cap && (unsigned)avail >= buffer_size)) {
            snd_pcm_sframes_t sframes;
            static const uint16_t psamples[2] = { 0, 0 };
            uint16_t csamples[2];

            if (cap == 0)
              sframes = snd_pcm_writei(pcm, psamples, 1);
            else
              sframes = snd_pcm_readi(pcm, csamples, 1);
            assert(sframes == 1);

            handled = 1;
            sample_count++;
        }

        if (!handled &&
            memcmp(&timestamp, &last_timestamp, sizeof(timestamp)) == 0 &&
            avail == last_avail &&
            delay == last_delay) {
            /* This is boring */
            continue;
        }

        now_us = timespec_us(&now);
        timestamp_us = timespec_us(&timestamp);

        if (cap == 0)
            pos = (unsigned long long) ((sample_count - handled - delay) * 1000000LU / 44100);
        else
            pos = (unsigned long long) ((sample_count - handled + delay) * 1000000LU / 44100);

        if (count++ % 50 == 0)
            printf("Elapsed\tCPU\tALSA\tPos\tSamples\tavail\tdelay\trevents\thandled\tstate\n");

        printf("%llu\t%llu\t%llu\t%llu\t%llu\t%li\t%li\t%i\t%i\t%i\n",
               (unsigned long long) (now_us - last_us),
               (unsigned long long) (now_us - start_us),
               (unsigned long long) (timestamp_us ? timestamp_us - start_us : 0),
               pos,
               (unsigned long long) sample_count,
               (signed long) avail,
               (signed long) delay,
               revents,
               handled,
               state);

        if (cap == 0)
          /** When this assert is hit, most likely something bad
           * happened, i.e. the avail jumped suddenly. */
          assert((unsigned) avail <= buffer_size);

        last_avail = avail;
        last_delay = delay;
        last_timestamp = timestamp;
        last_us = now_us;
    }

    return 0;
}
Example #5
0
static int ao_alsa_init(dtaudio_output_t *aout, dtaudio_para_t *para)
{
    memcpy(&wrapper->para, para, sizeof(dtaudio_para_t));
    snd_pcm_t *alsa_handle;
    snd_pcm_hw_params_t *alsa_hwparams;
    snd_pcm_sw_params_t *alsa_swparams;
    snd_pcm_uframes_t size;
    snd_pcm_uframes_t boundary;

    alsa_ctx_t *ctx = (alsa_ctx_t *)malloc(sizeof(*ctx));
    if (!ctx) {
        return -1;
    }
    wrapper->ao_priv = ctx;

    int afmt = format_to_alsa(wrapper->para.bps);
    uint32_t channels = wrapper->para.dst_channels;
    uint32_t sr = wrapper->para.dst_samplerate;
    int bytes_per_sample = snd_pcm_format_physical_width(afmt) * channels / 8;

    int err = 0;
    err = snd_pcm_open(&alsa_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        free(ctx);
        wrapper->ao_priv = NULL;
        return -1;
    }

    snd_pcm_hw_params_alloca(&alsa_hwparams);
    snd_pcm_sw_params_alloca(&alsa_swparams);

    err = snd_pcm_hw_params_any(alsa_handle, alsa_hwparams);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    err = snd_pcm_hw_params_set_access(alsa_handle, alsa_hwparams,
                                       SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    err = snd_pcm_hw_params_set_format(alsa_handle, alsa_hwparams, afmt);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    err = snd_pcm_hw_params_set_channels_near(alsa_handle, alsa_hwparams,
            &channels);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    err = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_hwparams, &sr, NULL);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    err = snd_pcm_hw_params(alsa_handle, alsa_hwparams);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
    /******************************************************************
     *  Set HW Params Finish
    ******************************************************************/

    /* buffer size means the entire size of alsa pcm buffer size*/
    err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &size);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    ctx->buf_size = size * bytes_per_sample;

    /*period size means count processed every interrupt*/
    err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &size, NULL);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
    ctx->trunk_size = size * bytes_per_sample;

    dt_info(TAG, "outburst: %d, bytes_per_sample: %d, buffersize: %d\n",
            ctx->trunk_size, bytes_per_sample, ctx->buf_size);

    /******************************************************************
    * set sw params
    ******************************************************************/
    err = snd_pcm_sw_params_current(alsa_handle, alsa_swparams);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
#if SND_LIB_VERSION >= 0x000901
    err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary);
#else
    boundary = 0x7fffffff;
#endif
    err = snd_pcm_sw_params_set_start_threshold(alsa_handle, alsa_swparams, size);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
    err = snd_pcm_sw_params_set_stop_threshold(alsa_handle, alsa_swparams,
            boundary);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
#if SND_LIB_VERSION >= 0x000901
    err = snd_pcm_sw_params_set_silence_size(alsa_handle, alsa_swparams, boundary);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
#endif

    err = snd_pcm_sw_params(alsa_handle, alsa_swparams);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    ctx->pause_support = snd_pcm_hw_params_can_pause(alsa_hwparams);

    //buf size limit
    ctx->buf_threshold = bytes_per_sample * sr * DEFAULT_TIME_SIZE / 1000;
    dt_info(TAG, "alsa audio init ok! outburst:%d thres:%d \n", ctx->trunk_size,
            ctx->buf_threshold);
    ctx->handle = alsa_handle;
    ctx->channels = wrapper->para.dst_channels;
    ctx->bps = wrapper->para.bps;
    ctx->samplerate = wrapper->para.dst_samplerate;
    return 0;
}
Example #6
0
static int initialize_device(struct audio_info_struct *ai)
{
    snd_pcm_hw_params_t *hw;
    int i;
    snd_pcm_format_t format;
    unsigned int rate;
    snd_pcm_uframes_t buffer_size;
    snd_pcm_uframes_t period_size;
    snd_pcm_sw_params_t *sw;
    snd_pcm_uframes_t boundary;

    snd_pcm_hw_params_alloca(&hw);
    if (snd_pcm_hw_params_any(ai->handle, hw) < 0) {
        fprintf(stderr, "initialize_device(): no configuration available\n");
        return -1;
    }
    if (snd_pcm_hw_params_set_access(ai->handle, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
        fprintf(stderr, "initialize_device(): device does not support interleaved access\n");
        return -1;
    }
    format = SND_PCM_FORMAT_UNKNOWN;
    for (i = 0; i < NUM_FORMATS; ++i) {
        if (ai->format == format_map[i].mpg123) {
            format = format_map[i].alsa;
            break;
        }
    }
    if (format == SND_PCM_FORMAT_UNKNOWN) {
        fprintf(stderr, "initialize_device(): invalid sample format %d\n", ai->format);
        errno = EINVAL;
        return -1;
    }
    if (snd_pcm_hw_params_set_format(ai->handle, hw, format) < 0) {
        fprintf(stderr, "initialize_device(): cannot set format %s\n", snd_pcm_format_name(format));
        return -1;
    }
    if (snd_pcm_hw_params_set_channels(ai->handle, hw, ai->channels) < 0) {
        fprintf(stderr, "initialize_device(): cannot set %d channels\n", ai->channels);
        return -1;
    }
    rate = ai->rate;
    if (snd_pcm_hw_params_set_rate_near(ai->handle, hw, &rate, NULL) < 0) {
        fprintf(stderr, "initialize_device(): cannot set rate %u\n", rate);
        return -1;
    }
    if (!rates_match(ai->rate, rate)) {
        fprintf(stderr, "initialize_device(): rate %ld not available, using %u\n", ai->rate, rate);
        /* return -1; */
    }
    buffer_size = rate * BUFFER_LENGTH;
    if (snd_pcm_hw_params_set_buffer_size_near(ai->handle, hw, &buffer_size) < 0) {
        fprintf(stderr, "initialize_device(): cannot set buffer size\n");
        return -1;
    }
    period_size = buffer_size / 4;
    if (snd_pcm_hw_params_set_period_size_near(ai->handle, hw, &period_size, NULL) < 0) {
        fprintf(stderr, "initialize_device(): cannot set period size\n");
        return -1;
    }
    if (snd_pcm_hw_params(ai->handle, hw) < 0) {
        fprintf(stderr, "initialize_device(): cannot set hw params\n");
        return -1;
    }

    snd_pcm_sw_params_alloca(&sw);
    if (snd_pcm_sw_params_current(ai->handle, sw) < 0) {
        fprintf(stderr, "initialize_device(): cannot get sw params\n");
        return -1;
    }
    /* start playing after the first write */
    if (snd_pcm_sw_params_set_start_threshold(ai->handle, sw, 1) < 0) {
        fprintf(stderr, "initialize_device(): cannot set start threshold\n");
        return -1;
    }
    if (snd_pcm_sw_params_get_boundary(sw, &boundary) < 0) {
        fprintf(stderr, "initialize_device(): cannot get boundary\n");
        return -1;
    }
    /* never stop on underruns */
    if (snd_pcm_sw_params_set_stop_threshold(ai->handle, sw, boundary) < 0) {
        fprintf(stderr, "initialize_device(): cannot set stop threshold\n");
        return -1;
    }
    /* wake up on every interrupt */
    if (snd_pcm_sw_params_set_avail_min(ai->handle, sw, 1) < 0) {
        fprintf(stderr, "initialize_device(): cannot set min avail\n");
        return -1;
    }
#if 0
    /* always write as many frames as possible */
    if (snd_pcm_sw_params_set_xfer_align(ai->handle, sw, 1) < 0) {
        fprintf(stderr, "initialize_device(): cannot set transfer alignment\n");
        return -1;
    }
#endif
    /* play silence when there is an underrun */
    if (snd_pcm_sw_params_set_silence_size(ai->handle, sw, boundary) < 0) {
        fprintf(stderr, "initialize_device(): cannot set silence size\n");
        return -1;
    }
    if (snd_pcm_sw_params(ai->handle, sw) < 0) {
        fprintf(stderr, "initialize_device(): cannot set sw params\n");
        return -1;
    }
    return 0;
}
Example #7
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;
    }
Example #8
0
/**
 * Allocate the memory-mapped buffer for direct sound, and set up the
 * callback.
 */
static int DSDB_CreateMMAP(IDsDriverBufferImpl* pdbi)
{
    snd_pcm_t *pcm = pdbi->pcm;
    snd_pcm_format_t format;
    snd_pcm_uframes_t frames, ofs, avail, psize, boundary;
    unsigned int channels, bits_per_sample, bits_per_frame;
    int err, mmap_mode;
    const snd_pcm_channel_area_t *areas;
    snd_pcm_hw_params_t *hw_params = pdbi->hw_params;
    snd_pcm_sw_params_t *sw_params = pdbi->sw_params;
    void *buf;

    mmap_mode = snd_pcm_type(pcm);

    if (mmap_mode == SND_PCM_TYPE_HW)
        TRACE("mmap'd buffer is a direct hardware buffer.\n");
    else if (mmap_mode == SND_PCM_TYPE_DMIX)
        TRACE("mmap'd buffer is an ALSA dmix buffer\n");
    else
        TRACE("mmap'd buffer is an ALSA type %d buffer\n", mmap_mode);

    err = snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL);

    err = snd_pcm_hw_params_get_format(hw_params, &format);
    err = snd_pcm_hw_params_get_buffer_size(hw_params, &frames);
    err = snd_pcm_hw_params_get_channels(hw_params, &channels);
    bits_per_sample = snd_pcm_format_physical_width(format);
    bits_per_frame = bits_per_sample * channels;

    if (TRACE_ON(dsalsa))
        ALSA_TraceParameters(hw_params, NULL, FALSE);

    TRACE("format=%s  frames=%ld  channels=%d  bits_per_sample=%d  bits_per_frame=%d\n",
          snd_pcm_format_name(format), frames, channels, bits_per_sample, bits_per_frame);

    pdbi->mmap_buflen_frames = frames;
    pdbi->mmap_buflen_bytes = snd_pcm_frames_to_bytes( pcm, frames );

    snd_pcm_sw_params_current(pcm, sw_params);
    snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 0);
    snd_pcm_sw_params_get_boundary(sw_params, &boundary);
    snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, boundary);
    snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, boundary);
    snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0);
    snd_pcm_sw_params_set_avail_min(pcm, sw_params, 0);
    err = snd_pcm_sw_params(pcm, sw_params);

    avail = snd_pcm_avail_update(pcm);
    if ((snd_pcm_sframes_t)avail < 0)
    {
        ERR("No buffer is available: %s.\n", snd_strerror(avail));
        return DSERR_GENERIC;
    }

    if (!pdbi->mmap)
    {
        buf = pdbi->mmap_buffer = HeapAlloc(GetProcessHeap(), 0, pdbi->mmap_buflen_bytes);
        if (!buf)
            return DSERR_OUTOFMEMORY;

        snd_pcm_format_set_silence(format, buf, pdbi->mmap_buflen_frames);
        pdbi->mmap_pos = 0;
    }
    else
    {
        err = snd_pcm_mmap_begin(pcm, &areas, &ofs, &avail);
        if ( err < 0 )
        {
            ERR("Can't map sound device for direct access: %s/%d\n", snd_strerror(err), err);
            return DSERR_GENERIC;
        }
        snd_pcm_format_set_silence(format, areas->addr, pdbi->mmap_buflen_frames);
        pdbi->mmap_pos = ofs + snd_pcm_mmap_commit(pcm, ofs, 0);
        pdbi->mmap_buffer = areas->addr;
    }

    TRACE("created mmap buffer of %ld frames (%d bytes) at %p\n",
        frames, pdbi->mmap_buflen_bytes, pdbi->mmap_buffer);

    return DS_OK;
}
Example #9
0
/*
    open & setup audio device
    return: 1=success 0=fail
*/
static int init(int rate_hz, int channels, int format, int flags)
{
    unsigned int alsa_buffer_time = 500000; /* 0.5 s */
    unsigned int alsa_fragcount = 16;
    int err;
    int block;
    strarg_t device;
    snd_pcm_uframes_t chunk_size;
    snd_pcm_uframes_t bufsize;
    snd_pcm_uframes_t boundary;
    const opt_t subopts[] = {
      {"block", OPT_ARG_BOOL, &block, NULL},
      {"device", OPT_ARG_STR, &device, str_maxlen},
      {NULL}
    };

    char alsa_device[ALSA_DEVICE_SIZE + 1];
    // make sure alsa_device is null-terminated even when using strncpy etc.
    memset(alsa_device, 0, ALSA_DEVICE_SIZE + 1);

    mp_msg(MSGT_AO,MSGL_V,"alsa-init: requested format: %d Hz, %d channels, %x\n", rate_hz,
	channels, format);
    alsa_handler = NULL;
#if SND_LIB_VERSION >= 0x010005
    mp_msg(MSGT_AO,MSGL_V,"alsa-init: using ALSA %s\n", snd_asoundlib_version());
#else
    mp_msg(MSGT_AO,MSGL_V,"alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR);
#endif

    snd_lib_error_set_handler(alsa_error_handler);

    ao_data.samplerate = rate_hz;
    ao_data.format = format;
    ao_data.channels = channels;

    switch (format)
      {
      case AF_FORMAT_S8:
	alsa_format = SND_PCM_FORMAT_S8;
	break;
      case AF_FORMAT_U8:
	alsa_format = SND_PCM_FORMAT_U8;
	break;
      case AF_FORMAT_U16_LE:
	alsa_format = SND_PCM_FORMAT_U16_LE;
	break;
      case AF_FORMAT_U16_BE:
	alsa_format = SND_PCM_FORMAT_U16_BE;
	break;
      case AF_FORMAT_AC3_LE:
      case AF_FORMAT_S16_LE:
      case AF_FORMAT_IEC61937_LE:
	alsa_format = SND_PCM_FORMAT_S16_LE;
	break;
      case AF_FORMAT_AC3_BE:
      case AF_FORMAT_S16_BE:
      case AF_FORMAT_IEC61937_BE:
	alsa_format = SND_PCM_FORMAT_S16_BE;
	break;
      case AF_FORMAT_U32_LE:
	alsa_format = SND_PCM_FORMAT_U32_LE;
	break;
      case AF_FORMAT_U32_BE:
	alsa_format = SND_PCM_FORMAT_U32_BE;
	break;
      case AF_FORMAT_S32_LE:
	alsa_format = SND_PCM_FORMAT_S32_LE;
	break;
      case AF_FORMAT_S32_BE:
	alsa_format = SND_PCM_FORMAT_S32_BE;
	break;
      case AF_FORMAT_U24_LE:
	alsa_format = SND_PCM_FORMAT_U24_3LE;
	break;
      case AF_FORMAT_U24_BE:
	alsa_format = SND_PCM_FORMAT_U24_3BE;
	break;
      case AF_FORMAT_S24_LE:
	alsa_format = SND_PCM_FORMAT_S24_3LE;
	break;
      case AF_FORMAT_S24_BE:
	alsa_format = SND_PCM_FORMAT_S24_3BE;
	break;
      case AF_FORMAT_FLOAT_LE:
	alsa_format = SND_PCM_FORMAT_FLOAT_LE;
	break;
      case AF_FORMAT_FLOAT_BE:
	alsa_format = SND_PCM_FORMAT_FLOAT_BE;
	break;
      case AF_FORMAT_MU_LAW:
	alsa_format = SND_PCM_FORMAT_MU_LAW;
	break;
      case AF_FORMAT_A_LAW:
	alsa_format = SND_PCM_FORMAT_A_LAW;
	break;

      default:
	alsa_format = SND_PCM_FORMAT_MPEG; //? default should be -1
	break;
      }

    //subdevice parsing
    // set defaults
    block = 1;
    /* switch for spdif
     * sets opening sequence for SPDIF
     * sets also the playback and other switches 'on the fly'
     * while opening the abstract alias for the spdif subdevice
     * 'iec958'
     */
    if (AF_FORMAT_IS_IEC61937(format)) {
	device.str = "iec958";
	mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3/iec61937/iec958, %i channels\n", channels);
    }
  else
        /* in any case for multichannel playback we should select
         * appropriate device
         */
        switch (channels) {
	case 1:
	case 2:
	  device.str = "default";
	  mp_msg(MSGT_AO,MSGL_V,"alsa-init: setup for 1/2 channel(s)\n");
	  break;
	case 4:
	  if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
	    // hack - use the converter plugin
	    device.str = "plug:surround40";
	  else
	    device.str = "surround40";
	  mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround40\n");
	  break;
	case 6:
	  if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
	    device.str = "plug:surround51";
	  else
	    device.str = "surround51";
	  mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround51\n");
	  break;
	case 8:
	  if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
	    device.str = "plug:surround71";
	  else
	    device.str = "surround71";
	  mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround71\n");
	  break;
	default:
	  device.str = "default";
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ChannelsNotSupported,channels);
        }
    device.len = strlen(device.str);
    if (subopt_parse(ao_subdevice, subopts) != 0) {
        print_help();
        return 0;
    }
    parse_device(alsa_device, device.str, device.len);

    mp_msg(MSGT_AO,MSGL_V,"alsa-init: using device %s\n", alsa_device);

    if (!alsa_handler) {
      int open_mode = block ? 0 : SND_PCM_NONBLOCK;
      int isac3 =  AF_FORMAT_IS_IEC61937(format);
      //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
      mp_msg(MSGT_AO,MSGL_V,"alsa-init: opening device in %sblocking mode\n", block ? "" : "non-");
      if ((err = try_open_device(alsa_device, open_mode, isac3)) < 0)
	{
	  if (err != -EBUSY && !block) {
	    mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_OpenInNonblockModeFailed);
	    if ((err = try_open_device(alsa_device, 0, isac3)) < 0) {
	      mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err));
	      return 0;
	    }
	  } else {
	    mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err));
	    return 0;
	  }
	}

      if ((err = snd_pcm_nonblock(alsa_handler, 0)) < 0) {
         mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSetBlockMode, snd_strerror(err));
      } else {
	mp_msg(MSGT_AO,MSGL_V,"alsa-init: device reopened in blocking mode\n");
      }

      snd_pcm_hw_params_alloca(&alsa_hwparams);
      snd_pcm_sw_params_alloca(&alsa_swparams);

      // setting hw-parameters
      if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetInitialParameters,
		 snd_strerror(err));
	  return 0;
	}

      err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,
					 SND_PCM_ACCESS_RW_INTERLEAVED);
      if (err < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetAccessType,
	       snd_strerror(err));
	return 0;
      }

      /* workaround for nonsupported formats
	 sets default format to S16_LE if the given formats aren't supported */
      if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams,
                                             alsa_format)) < 0)
      {
         mp_msg(MSGT_AO,MSGL_INFO,
		MSGTR_AO_ALSA_FormatNotSupportedByHardware, af_fmt2str_short(format));
         alsa_format = SND_PCM_FORMAT_S16_LE;
         if (AF_FORMAT_IS_AC3(ao_data.format))
           ao_data.format = AF_FORMAT_AC3_LE;
         else if (AF_FORMAT_IS_IEC61937(ao_data.format))
           ao_data.format = AF_FORMAT_IEC61937_LE;
         else
         ao_data.format = AF_FORMAT_S16_LE;
      }

      if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams,
					      alsa_format)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetFormat,
		 snd_strerror(err));
	  return 0;
	}

      if ((err = snd_pcm_hw_params_set_channels_near(alsa_handler, alsa_hwparams,
						     &ao_data.channels)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetChannels,
		 snd_strerror(err));
	  return 0;
	}

      /* workaround for buggy rate plugin (should be fixed in ALSA 1.0.11)
         prefer our own resampler, since that allows users to choose the resampler,
         even per file if desired */
#if SND_LIB_VERSION >= 0x010009
      if ((err = snd_pcm_hw_params_set_rate_resample(alsa_handler, alsa_hwparams,
						     0)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToDisableResampling,
		 snd_strerror(err));
	  return 0;
	}
#endif

      if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams,
						 &ao_data.samplerate, NULL)) < 0)
        {
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSamplerate2,
		 snd_strerror(err));
	  return 0;
        }

      bytes_per_sample = af_fmt2bits(ao_data.format) / 8;
      bytes_per_sample *= ao_data.channels;
      ao_data.bps = ao_data.samplerate * bytes_per_sample;

	if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams,
							  &alsa_buffer_time, NULL)) < 0)
	  {
	    mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetBufferTimeNear,
		   snd_strerror(err));
	    return 0;
	  }

	if ((err = snd_pcm_hw_params_set_periods_near(alsa_handler, alsa_hwparams,
						      &alsa_fragcount, NULL)) < 0) {
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetPeriods,
		 snd_strerror(err));
	  return 0;
	}

      /* finally install hardware parameters */
      if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetHwParameters,
		 snd_strerror(err));
	  return 0;
	}
      // end setting hw-params


      // gets buffersize for control
      if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBufferSize, snd_strerror(err));
	  return 0;
	}
      else {
	ao_data.buffersize = bufsize * bytes_per_sample;
	  mp_msg(MSGT_AO,MSGL_V,"alsa-init: got buffersize=%i\n", ao_data.buffersize);
      }

      if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetPeriodSize, snd_strerror(err));
	return 0;
      } else {
	mp_msg(MSGT_AO,MSGL_V,"alsa-init: got period size %li\n", chunk_size);
      }
      ao_data.outburst = chunk_size * bytes_per_sample;

      /* setting software parameters */
      if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters,
	       snd_strerror(err));
	return 0;
      }
#if SND_LIB_VERSION >= 0x000901
      if ((err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBoundary,
	       snd_strerror(err));
	return 0;
      }
#else
      boundary = 0x7fffffff;
#endif
      /* start playing when one period has been written */
      if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, chunk_size)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStartThreshold,
	       snd_strerror(err));
	return 0;
      }
      /* disable underrun reporting */
      if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, boundary)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStopThreshold,
	       snd_strerror(err));
	return 0;
      }
#if SND_LIB_VERSION >= 0x000901
      /* play silence when there is an underrun */
      if ((err = snd_pcm_sw_params_set_silence_size(alsa_handler, alsa_swparams, boundary)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSilenceSize,
	       snd_strerror(err));
	return 0;
      }
#endif
      if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters,
	       snd_strerror(err));
	return 0;
      }
      /* end setting sw-params */

      mp_msg(MSGT_AO,MSGL_V,"alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
	     ao_data.samplerate, ao_data.channels, (int)bytes_per_sample, ao_data.buffersize,
	     snd_pcm_format_description(alsa_format));

    } // end switch alsa_handler (spdif)
    alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
    return 1;
} // end init
Example #10
0
/* setup alsa data transfer behavior */
static inline int alsa_set_swparams(ao_device *device)
{
	ao_alsa_internal *internal  = (ao_alsa_internal *) device->internal;
	snd_pcm_sw_params_t *params;
        snd_pcm_uframes_t boundary;
	int err;

	/* allocate the software parameter structure */
	snd_pcm_sw_params_alloca(&params);

	/* fetch the current software parameters */
	err = snd_pcm_sw_params_current(internal->pcm_handle, params);
	if (err < 0){
          adebug("snd_pcm_sw_params_current() failed.\n");
          return err;
        }

#if 0 /* the below causes more trouble than it cures */
	/* allow transfers to start when there is one period */
	err = snd_pcm_sw_params_set_start_threshold(internal->pcm_handle,
                                                    params, internal->period_size);
	if (err < 0){
          adebug("snd_pcm_sw_params_set_start_threshold() failed.\n");
          //return err;
        }

	/* require a minimum of one full transfer in the buffer */
	err = snd_pcm_sw_params_set_avail_min(internal->pcm_handle, params,
                                              internal->period_size);
	if (err < 0){
          adebug("snd_pcm_sw_params_set_avail_min() failed.\n");
          //return err;
        }
#endif

	/* do not align transfers; this is obsolete/deprecated in ALSA
           1.x where the transfer alignemnt is always 1 (except for
           buggy drivers like VIA 82xx which still demand aligned
           transfers regardless of setting, in violation of the ALSA
           API docs) */
	err = snd_pcm_sw_params_set_xfer_align(internal->pcm_handle, params, 1);
	if (err < 0){
          adebug("snd_pcm_sw_params_set_xfer_align() failed.\n");
          //return err;
        }


        /* get the boundary size */
        err = snd_pcm_sw_params_get_boundary(params,&boundary);
	if (err < 0){
          adebug("snd_pcm_sw_params_get_boundary() failed.\n");
        }else{

          /* force a work-ahead silence buffer; this is a fix, again for
             VIA 82xx, where non-MMIO transfers will buffer into
             period-size transfers, but the last transfer is usually
             undersized and playback falls off the end of the submitted
             data. */
          err = snd_pcm_sw_params_set_silence_size(internal->pcm_handle, params, boundary);
          if (err < 0){
            adebug("snd_pcm_sw_params_set_silence_size() failed.\n");
            //return err;
          }
        }

	/* commit the params structure to ALSA */
	err = snd_pcm_sw_params(internal->pcm_handle, params);
	if (err < 0){
          adebug("snd_pcm_sw_params() failed.\n");
          return err;
        }

	return 1;
}
Example #11
0
static int sndo_pcm_initialize(sndo_pcm_t *pcm)
{
	int err;
	snd_pcm_uframes_t boundary;
	snd_pcm_uframes_t p_period_size = ~0UL, c_period_size = ~0UL;
	snd_pcm_uframes_t p_buffer_size = ~0UL, c_buffer_size = ~0UL;

	if (pcm->playback) {
		err = snd_pcm_hw_params(pcm->playback, pcm->p_hw_params);
		if (err < 0)
			return err;
		err = snd_pcm_hw_params_get_period_size(pcm->p_hw_params, &p_period_size, NULL);
		if (err < 0)
			return err;
		err = snd_pcm_hw_params_get_buffer_size(pcm->p_hw_params, &p_buffer_size);
		if (err < 0)
			return err;
	}
	if (pcm->capture) {
		err = snd_pcm_hw_params(pcm->capture, pcm->c_hw_params);
		if (err < 0)
			return err;
		err = snd_pcm_hw_params_get_period_size(pcm->c_hw_params, &c_period_size, NULL);
		if (err < 0)
			return err;
		err = snd_pcm_hw_params_get_buffer_size(pcm->c_hw_params, &c_buffer_size);
		if (err < 0)
			return err;
	}
	if (p_period_size < c_period_size)
		pcm->transfer_block = p_period_size;
	else
		pcm->transfer_block = c_period_size;
	if (p_buffer_size < c_buffer_size)
		pcm->ring_size = p_buffer_size;
	else
		pcm->ring_size = c_buffer_size;
	if (pcm->playback) {
		err = snd_pcm_sw_params_get_boundary(pcm->p_sw_params, &boundary);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_start_threshold(pcm->playback, pcm->p_sw_params, boundary);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_stop_threshold(pcm->playback, pcm->p_sw_params, pcm->xrun == SNDO_PCM_XRUN_IGNORE ? boundary : pcm->ring_size);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_xfer_align(pcm->playback, pcm->p_sw_params, 1);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_avail_min(pcm->playback, pcm->p_sw_params, pcm->transfer_block);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params(pcm->playback, pcm->p_sw_params);
		if (err < 0)
			return err;
	}
	if (pcm->capture) {
		err = snd_pcm_sw_params_get_boundary(pcm->c_sw_params, &boundary);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_start_threshold(pcm->capture, pcm->c_sw_params, boundary);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_stop_threshold(pcm->capture, pcm->c_sw_params, pcm->xrun == SNDO_PCM_XRUN_IGNORE ? boundary : pcm->ring_size);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_xfer_align(pcm->capture, pcm->c_sw_params, 1);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_avail_min(pcm->capture, pcm->c_sw_params, pcm->transfer_block);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params(pcm->capture, pcm->c_sw_params);
		if (err < 0)
			return err;
	}
	pcm->initialized = 1;
	return 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;
    }