/* Using ALSA with threads test program
   Copyright (C) 2007 Trent Piepho <xyzzy@speakeasy.org> */

/* To compile, provide the path to the alsa-lib include directory. e.g.
   gcc -O2 -Wall -Ialsa-lib/include -pthread test_hwparams.c
   This is necessary to get the types and defines for using the ALSA
   device directly.  The alsa kernel includes don't work from userspace. */


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <stdarg.h>
#include <limits.h>
#include <pthread.h>
#include "local.h"
#include "sound/asound.h"
#include "global.h"
#include "input.h"
#include "output.h"
#include "conf.h"
#include "pcm.h"

static const char *dev = "/dev/snd/pcmC1D0p";

struct hw_params_args {
    int fd;
    int periods;
    int period_size;
};

static void *hw_params(void *arg)
{
    struct hw_params_args *args = arg;
    snd_pcm_hw_params_t params = {.rmask = ~0U, .info = ~0U};
    struct _snd_interval *interval;
    int r;

    memset(params.masks, 0xff, SNDRV_MASK_MAX/8 *
           (SNDRV_PCM_HW_PARAM_LAST_MASK - SNDRV_PCM_HW_PARAM_FIRST_MASK + 1));
    for(r=0; r<=SNDRV_PCM_HW_PARAM_LAST_INTERVAL-SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; r++)
	params.intervals[r].max = UINT_MAX;

    interval = params.intervals + (SNDRV_PCM_HW_PARAM_PERIOD_SIZE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL);
    interval->min = interval->max = args->period_size;
    interval = params.intervals + (SNDRV_PCM_HW_PARAM_PERIODS - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL);
    interval->min = interval->max = args->periods;
    r = ioctl(args->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params);
    printf("hw_params = %d\n", r);
    return NULL;
}

static void *prepare(void *arg)
{
    int fd = (int)arg, r;

    r = ioctl(fd, SNDRV_PCM_IOCTL_PREPARE);
    printf("prepare = %d\n", r);
    return NULL;
}

int main(int argc, char *argv[])
{
    int fd;
    pthread_t thread;
    struct hw_params_args arg1, arg2;

    if(argc>1) dev = argv[1];

    fd = open(dev, O_RDWR);
    printf("fd = %d\n", fd);

    arg1.fd = arg2.fd = fd;
    arg1.period_size = 1024; arg1.periods = 128;
    arg2.period_size = 128*1024; arg2.periods = 1;
    pthread_create(&thread, NULL, hw_params, &arg1);
    hw_params(&arg2);
    pthread_join(thread, NULL);

    prepare((void*)fd);
    return 0;
}
