示例#1
0
文件: qsa.c 项目: Sponk/NeoEditor
static void deviceList(int type, vector_DevMap *devmap)
{
    snd_ctl_t* handle;
    snd_pcm_info_t pcminfo;
    int max_cards, card, err, dev;
    DevMap entry;
    char name[1024];
    struct snd_ctl_hw_info info;
    void* temp;

    max_cards = snd_cards();
    if(max_cards < 0)
        return;

    VECTOR_RESERVE(*devmap, max_cards+1);
    VECTOR_RESIZE(*devmap, 0);

    entry.name = strdup(qsaDevice);
    entry.card = 0;
    entry.dev = 0;
    VECTOR_PUSH_BACK(*devmap, entry);

    for(card = 0;card < max_cards;card++)
    {
        if((err=snd_ctl_open(&handle, card)) < 0)
            continue;

        if((err=snd_ctl_hw_info(handle, &info)) < 0)
        {
            snd_ctl_close(handle);
            continue;
        }

        for(dev = 0;dev < (int)info.pcmdevs;dev++)
        {
            if((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0)
                continue;

            if((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) ||
               (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE)))
            {
                snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev);
                entry.name = strdup(name);
                entry.card = card;
                entry.dev = dev;

                VECTOR_PUSH_BACK(*devmap, entry);
                TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev);
            }
        }
        snd_ctl_close(handle);
    }
}
示例#2
0
static int
QSA_Init(SDL_AudioDriverImpl * impl)
{
    snd_pcm_t *handle = NULL;
    int32_t status = 0;

    /* Clear devices array */
    SDL_memset(qsa_playback_device, 0x00,
               sizeof(QSA_Device) * QSA_MAX_DEVICES);
    SDL_memset(qsa_capture_device, 0x00,
               sizeof(QSA_Device) * QSA_MAX_DEVICES);
    qsa_playback_devices = 0;
    qsa_capture_devices = 0;

    /* Set function pointers                                     */
    /* DeviceLock and DeviceUnlock functions are used default,   */
    /* provided by SDL, which uses pthread_mutex for lock/unlock */
    impl->DetectDevices = QSA_DetectDevices;
    impl->OpenDevice = QSA_OpenDevice;
    impl->ThreadInit = QSA_ThreadInit;
    impl->WaitDevice = QSA_WaitDevice;
    impl->PlayDevice = QSA_PlayDevice;
    impl->GetDeviceBuf = QSA_GetDeviceBuf;
    impl->CloseDevice = QSA_CloseDevice;
    impl->WaitDone = QSA_WaitDone;
    impl->Deinitialize = QSA_Deinitialize;
    impl->LockDevice = NULL;
    impl->UnlockDevice = NULL;

    impl->OnlyHasDefaultOutputDevice = 0;
    impl->ProvidesOwnCallbackThread = 0;
    impl->SkipMixerLock = 0;
    impl->HasCaptureSupport = 1;
    impl->OnlyHasDefaultOutputDevice = 0;
    impl->OnlyHasDefaultInputDevice = 0;

    /* Check if io-audio manager is running or not */
    status = snd_cards();
    if (status == 0) {
        /* if no, return immediately */
        return 1;
    }

    return 1;   /* this audio target is available. */
}
示例#3
0
static void
QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
{
    uint32_t it;
    uint32_t cards;
    uint32_t devices;
    int32_t status;

    /* Detect amount of available devices       */
    /* this value can be changed in the runtime */
    cards = snd_cards();

    /* If io-audio manager is not running we will get 0 as number */
    /* of available audio devices                                 */
    if (cards == 0) {
        /* We have no any available audio devices */
        return;
    }

    /* Find requested devices by type */
    if (!iscapture) {
        /* Playback devices enumeration requested */
        for (it = 0; it < cards; it++) {
            devices = 0;
            do {
                status =
                    snd_card_get_longname(it,
                                          qsa_playback_device
                                          [qsa_playback_devices].name,
                                          QSA_MAX_NAME_LENGTH);
                if (status == EOK) {
                    snd_pcm_t *handle;

                    /* Add device number to device name */
                    sprintf(qsa_playback_device[qsa_playback_devices].name +
                            SDL_strlen(qsa_playback_device
                                       [qsa_playback_devices].name), " d%d",
                            devices);

                    /* Store associated card number id */
                    qsa_playback_device[qsa_playback_devices].cardno = it;

                    /* Check if this device id could play anything */
                    status =
                        snd_pcm_open(&handle, it, devices,
                                     SND_PCM_OPEN_PLAYBACK);
                    if (status == EOK) {
                        qsa_playback_device[qsa_playback_devices].deviceno =
                            devices;
                        status = snd_pcm_close(handle);
                        if (status == EOK) {
                            addfn(qsa_playback_device[qsa_playback_devices].name);
                            qsa_playback_devices++;
                        }
                    } else {
                        /* Check if we got end of devices list */
                        if (status == -ENOENT) {
                            break;
                        }
                    }
                } else {
                    break;
                }

                /* Check if we reached maximum devices count */
                if (qsa_playback_devices >= QSA_MAX_DEVICES) {
                    break;
                }
                devices++;
            } while (1);

            /* Check if we reached maximum devices count */
            if (qsa_playback_devices >= QSA_MAX_DEVICES) {
                break;
            }
        }
    } else {
        /* Capture devices enumeration requested */
        for (it = 0; it < cards; it++) {
            devices = 0;
            do {
                status =
                    snd_card_get_longname(it,
                                          qsa_capture_device
                                          [qsa_capture_devices].name,
                                          QSA_MAX_NAME_LENGTH);
                if (status == EOK) {
                    snd_pcm_t *handle;

                    /* Add device number to device name */
                    sprintf(qsa_capture_device[qsa_capture_devices].name +
                            SDL_strlen(qsa_capture_device
                                       [qsa_capture_devices].name), " d%d",
                            devices);

                    /* Store associated card number id */
                    qsa_capture_device[qsa_capture_devices].cardno = it;

                    /* Check if this device id could play anything */
                    status =
                        snd_pcm_open(&handle, it, devices,
                                     SND_PCM_OPEN_CAPTURE);
                    if (status == EOK) {
                        qsa_capture_device[qsa_capture_devices].deviceno =
                            devices;
                        status = snd_pcm_close(handle);
                        if (status == EOK) {
                            addfn(qsa_capture_device[qsa_capture_devices].name);
                            qsa_capture_devices++;
                        }
                    } else {
                        /* Check if we got end of devices list */
                        if (status == -ENOENT) {
                            break;
                        }
                    }

                    /* Check if we reached maximum devices count */
                    if (qsa_capture_devices >= QSA_MAX_DEVICES) {
                        break;
                    }
                } else {
                    break;
                }
                devices++;
            } while (1);

            /* Check if we reached maximum devices count */
            if (qsa_capture_devices >= QSA_MAX_DEVICES) {
                break;
            }
        }
    }
}
示例#4
0
/*
    open & setup audio device
    return: 1=success 0=fail
*/
static int init(int rate_hz, int channels, int format, int flags)
{
    int err;
    int cards = -1;
    snd_pcm_channel_params_t params;
    snd_pcm_channel_setup_t setup;
    snd_pcm_info_t info;
    snd_pcm_channel_info_t chninfo;

    mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_ALSA5_InitInfo, rate_hz,
	channels, af_fmt2str_short(format));

    alsa_handler = NULL;

    mp_msg(MSGT_AO, MSGL_V, "alsa-init: compiled for ALSA-%s (%d)\n", SND_LIB_VERSION_STR,
        SND_LIB_VERSION);

    if ((cards = snd_cards()) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_SoundCardNotFound);
	return 0;
    }

    ao_data.format = format;
    ao_data.channels = channels;
    ao_data.samplerate = rate_hz;
    ao_data.bps = ao_data.samplerate*ao_data.channels;
    ao_data.outburst = OUTBURST;
    ao_data.buffersize = 16384;

    memset(&alsa_format, 0, sizeof(alsa_format));
    switch (format)
    {
	case AF_FORMAT_S8:
	    alsa_format.format = SND_PCM_SFMT_S8;
	    break;
	case AF_FORMAT_U8:
	    alsa_format.format = SND_PCM_SFMT_U8;
	    break;
	case AF_FORMAT_U16_LE:
	    alsa_format.format = SND_PCM_SFMT_U16_LE;
	    break;
	case AF_FORMAT_U16_BE:
	    alsa_format.format = SND_PCM_SFMT_U16_BE;
	    break;
	case AF_FORMAT_AC3_LE:
	case AF_FORMAT_S16_LE:
	    alsa_format.format = SND_PCM_SFMT_S16_LE;
	    break;
	case AF_FORMAT_AC3_BE:
	case AF_FORMAT_S16_BE:
	    alsa_format.format = SND_PCM_SFMT_S16_BE;
	    break;
	default:
	    alsa_format.format = SND_PCM_SFMT_MPEG;
	    break;
    }

    switch(alsa_format.format)
    {
	case SND_PCM_SFMT_S16_LE:
	case SND_PCM_SFMT_U16_LE:
	    ao_data.bps *= 2;
	    break;
	case -1:
	    mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_InvalidFormatReq,af_fmt2str_short(format));
	    return 0;
	default:
	    break;
    }

    switch(rate_hz)
    {
	case 8000:
	    alsa_rate = SND_PCM_RATE_8000;
	    break;
	case 11025:
	    alsa_rate = SND_PCM_RATE_11025;
	    break;
	case 16000:
	    alsa_rate = SND_PCM_RATE_16000;
	    break;
	case 22050:
	    alsa_rate = SND_PCM_RATE_22050;
	    break;
	case 32000:
	    alsa_rate = SND_PCM_RATE_32000;
	    break;
	case 44100:
	    alsa_rate = SND_PCM_RATE_44100;
	    break;
	case 48000:
	    alsa_rate = SND_PCM_RATE_48000;
	    break;
	case 88200:
	    alsa_rate = SND_PCM_RATE_88200;
	    break;
	case 96000:
	    alsa_rate = SND_PCM_RATE_96000;
	    break;
	case 176400:
	    alsa_rate = SND_PCM_RATE_176400;
	    break;
	case 192000:
	    alsa_rate = SND_PCM_RATE_192000;
	    break;
	default:
	    alsa_rate = SND_PCM_RATE_CONTINUOUS;
	    break;
    }

    alsa_format.rate = ao_data.samplerate;
    alsa_format.voices = ao_data.channels;
    alsa_format.interleave = 1;

    if ((err = snd_pcm_open(&alsa_handler, 0, 0, SND_PCM_OPEN_PLAYBACK)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PlayBackError, snd_strerror(err));
	return 0;
    }

    if ((err = snd_pcm_info(alsa_handler, &info)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PcmInfoError, snd_strerror(err));
	return 0;
    }

    mp_msg(MSGT_AO, MSGL_INFO, MSGTR_AO_ALSA5_SoundcardsFound,
	cards, info.name);

    if (info.flags & SND_PCM_INFO_PLAYBACK)
    {
	memset(&chninfo, 0, sizeof(chninfo));
	chninfo.channel = SND_PCM_CHANNEL_PLAYBACK;
	if ((err = snd_pcm_channel_info(alsa_handler, &chninfo)) < 0)
	{
	    mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PcmChanInfoError, snd_strerror(err));
	    return 0;
	}

#ifndef __QNX__
	if (chninfo.buffer_size)
	    ao_data.buffersize = chninfo.buffer_size;
#endif

	mp_msg(MSGT_AO, MSGL_V, "alsa-init: setting preferred buffer size from driver: %d bytes\n",
	    ao_data.buffersize);
    }

    memset(&params, 0, sizeof(params));
    params.channel = SND_PCM_CHANNEL_PLAYBACK;
    params.mode = SND_PCM_MODE_STREAM;
    params.format = alsa_format;
    params.start_mode = SND_PCM_START_DATA;
    params.stop_mode = SND_PCM_STOP_ROLLOVER;
    params.buf.stream.queue_size = ao_data.buffersize;
    params.buf.stream.fill = SND_PCM_FILL_NONE;

    if ((err = snd_pcm_channel_params(alsa_handler, &params)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_CantSetParms, snd_strerror(err));
	return 0;
    }

    memset(&setup, 0, sizeof(setup));
    setup.channel = SND_PCM_CHANNEL_PLAYBACK;
    setup.mode = SND_PCM_MODE_STREAM;
    setup.format = alsa_format;
    setup.buf.stream.queue_size = ao_data.buffersize;
    setup.msbits_per_sample = ao_data.bps;

    if ((err = snd_pcm_channel_setup(alsa_handler, &setup)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_CantSetChan, snd_strerror(err));
	return 0;
    }

    if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0)
    {
	mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_ChanPrepareError, snd_strerror(err));
	return 0;
    }

    mp_msg(MSGT_AO, MSGL_INFO, "AUDIO: %d Hz/%d channels/%d bps/%d bytes buffer/%s\n",
	ao_data.samplerate, ao_data.channels, ao_data.bps, ao_data.buffersize,
	snd_pcm_get_format_name(alsa_format.format));
    return 1;
}
示例#5
0
/* Plays a sound with the Advanced Linux Sound Architecture, ALSA.
   Returns 0 on successful playback, nonzero on error. */
int PlayerALSA(u_int8_t *samples, unsigned int bits, unsigned int channels,
               unsigned int rate, unsigned int bytes)
{
    int i;

    /* ALSA is a bit verbose, and it tends to require
       lots of structures. */
    unsigned int alsa_device = 0, alsa_card = 0;
    char *alsa_card_name;
    snd_ctl_t *alsa_ctl;
    snd_ctl_hw_info_t alsa_hw_info;
    snd_pcm_t *alsa_pcm;
    snd_pcm_channel_params_t alsa_params;
	
    /* Playback status variables. */
    unsigned int position;

    /* Scan for ALSA cards and devices. Each card has an integer ID
       less than snd_cards(). We scan for the first available card
       in order to demonstrate ALSA's organization, but we could
       find the default card and PCM device numbers immediately with
       the snd_defaults_pcm_card(), snd_defaults_pcm_device() functions. */
    alsa_pcm = NULL;
    for (alsa_card = 0; alsa_card < (unsigned)snd_cards(); alsa_card++) {

	/* Try to open this card. */
	if (snd_ctl_open(&alsa_ctl,alsa_card) < 0)
	    continue;
		
	/* Retrieve card info. */
	if (snd_ctl_hw_info(alsa_ctl,&alsa_hw_info) < 0) {
	    snd_ctl_close(alsa_ctl);
	    continue;
	}
		
	snd_ctl_close(alsa_ctl);
		
	/* Find a suitable device on this card. */
	alsa_pcm = NULL;
	for (alsa_device = 0; alsa_device < alsa_hw_info.pcmdevs; alsa_device++) {
	    if (snd_pcm_open(&alsa_pcm,alsa_card,
			     alsa_device,SND_PCM_OPEN_PLAYBACK) < 0) continue;
	    
	    /* Device successfully opened. */
	    break;
	}
		
	if (alsa_pcm != NULL) break;
    }
	
    /* Were we able to open a device? */
    if (alsa_card == (unsigned)snd_cards()) {
	printf("ALSA player: unable to find a configured device.\n");
	return -1;
    }
	
    /* Print info about the device. */
    if (snd_card_get_longname(alsa_card,&alsa_card_name) < 0)
	alsa_card_name = "(unknown)";
    printf("ALSA player: using device %i:%i (%s)\n",
	   alsa_card, alsa_device, alsa_card_name);
	
    /* Configure the device for the loaded sound data. */
    memset(&alsa_params,0,sizeof (alsa_params));
    alsa_params.channel = SND_PCM_CHANNEL_PLAYBACK;

    /* Use stream mode. In this mode, we don't have to give ALSA complete
       blocks; we can send it data as we get it. Block mode is needed for
       mmap() functionality. Unlike OSS, ALSA's mmap() functionality is
       quite reliable, and easily accessible through library functions.
       We won't use it here, though; there's no need. */
    alsa_params.mode = SND_PCM_MODE_STREAM;
    alsa_params.format.interleave = 1;
    
    /* We'll assume little endian samples. You may wish to use the data in
       the GNU C Library's endian.h to support other endiannesses. We're
       ignoring that case for simplicity. */
    if (bits == 8)
	alsa_params.format.format = SND_PCM_SFMT_U8;
    else if (bits == 16)
	alsa_params.format.format = SND_PCM_SFMT_S16_LE;
    else {
	printf("ALSA player: invalid sample size.\n");
	return -1;
    }
    alsa_params.format.rate = rate;
    alsa_params.format.voices = channels;
    alsa_params.start_mode = SND_PCM_START_DATA;
    alsa_params.stop_mode = SND_PCM_STOP_ROLLOVER;
    alsa_params.buf.block.frag_size = 4096;
    alsa_params.buf.block.frags_min = 1;
    alsa_params.buf.block.frags_max = 2;
	
    if ((i = snd_pcm_plugin_params(alsa_pcm,&alsa_params)) < 0) {
	printf("ALSA player: unable to set parameters.\n");
	snd_pcm_close(alsa_pcm);
	return -1;
    }

    if (snd_pcm_plugin_prepare(alsa_pcm, SND_PCM_CHANNEL_PLAYBACK) < 0) {
	printf("ALSA player: unable to prepare playback.\n");
	snd_pcm_close(alsa_pcm);
	return -1;
    }
	
    /* Feed the sound data to ALSA. */
    position = 0;
    while (position < bytes) {
	int written, blocksize;
		
	if (bytes-position < 4096)
	    blocksize = bytes-position;
	else
	    blocksize = 4096;
		
	/* Write to the sound device. */
	written = snd_pcm_plugin_write(alsa_pcm, &samples[position], blocksize);

	/* If ALSA can't take any more data right now, it'll return -EAGAIN.
	   If this were sound code for a game, we'd probably just contine the
	   game loop and try to write data the next time around.
	   In a game, you'd probably also want to put the device in nonblocking
	   mode (see the snd_pcm_nonblock_mode() function). */
	if (written == -EAGAIN) {
	    /* Waste some time. This keeps us from using 100% CPU. */
	    usleep(1000);

	    written = 0;
	} else {
	    if (written < 0) {
		perror("\nALSA player: error writing to sound device");
		snd_pcm_close(alsa_pcm);
		return -1;
	    }
	}

	/* Update the position. */
	position += written;

	/* Print some information. */
	WritePlaybackStatus(position, bytes, channels, bits, rate);
	printf("\r");
	fflush(stdout);
    }

    printf("\n");

    /* Wait until ALSA's internal buffers are empty, then stop playback.
       This will make sure that the entire sound clip has played. */
    snd_pcm_channel_flush(alsa_pcm, SND_PCM_CHANNEL_PLAYBACK);
    snd_pcm_close(alsa_pcm);

    return 0;
}
示例#6
0
int alsa_init(audiodevice_t *dev, int cardno, int pcmdev, int mixdev, boolean automix) {
	snd_ctl_t *ctl_handle;
	snd_ctl_hw_info_t *hwinfo;
	audio_alsa05_t *alsa;
	int i, j, ncards;
	snd_pcm_t *pcm_handle;
	
	/* サウンドカードが存在するかチェック */
	ncards = snd_cards();
	if (ncards < 1) {
		WARNING("No ALSA device found\n");
		return NG;
	}
	
	if (cardno == -1 && pcmdev == -1) {
		/* 最初に見つかった使用可能なカード */
		if (NULL == (hwinfo = (snd_ctl_hw_info_t *)malloc(sizeof(*hwinfo) * ncards))) {
			NOMEMERR();
			return NG;
		}
		for (i = 0; i < ncards; i++) {
			if (0 > snd_ctl_open(&ctl_handle, i)) {
				WARNING("Can't Open Card %d\n", i);
				free(hwinfo);
				return NG;
			}
			if (0 > snd_ctl_hw_info(ctl_handle, hwinfo + i)) {
				WARNING("Can't Get Card(%d) info\n", i);
				free(hwinfo);
				return NG;
			}
			snd_ctl_close(ctl_handle);
			for (j = 0; j < hwinfo[i].pcmdevs; j++) {
				//open してチェック OK なら outへ
				if (0 > snd_pcm_open(&pcm_handle, i, j, SND_PCM_OPEN_PLAYBACK)) continue;
				cardno = i; pcmdev  = j;
				snd_pcm_close(pcm_handle);
				NOTICE("ALSA Use(%d:%d) device\n", i, j);
				goto out;
			}
		}
		// 使用可能なデバイスが1つもない場合
		WARNING("Can't Get Card(%d) info\n", i);
		return NG;
	out:
		free(hwinfo);
	} else {
		/* 指定のカード */
		if (0 > snd_ctl_open(&ctl_handle, cardno)) {
			WARNING("Can't Open Card %d\n", cardno);
			return NG;
		}
		snd_ctl_close(ctl_handle);
		
		/* 指定の pcmdevice がカードの中にあるかどうか */
		if (pcmdev >= 0 && pcmdev < hwinfo[cardno].pcmdevs) {
			//opne してチェック
			if (0 > snd_pcm_open(&pcm_handle, cardno, pcmdev, SND_PCM_OPEN_PLAYBACK)) {
				WARNING("Can't Open (%d:%d)\n", cardno, pcmdev);
				return NG;
			}
			snd_pcm_close(pcm_handle);
			NOTICE("ALSA Use(%d:%d) device\n", cardno, pcmdev);
		} else {
			WARNING("Can't Open (%d:%d)\n", cardno, pcmdev);
			return NG;
		}
	}
	
	if (mixer_init(dev, cardno, mixdev, &hwinfo) < 0) {
		return NG;
	}
	
	alsa = g_new0(audio_alsa05_t, 1);
	
	alsa->card = cardno;
	alsa->pcm_dev = pcmdev;
	alsa->automixer = automix;
	
	dev->data_pcm = alsa;
	
	dev->id      = AUDIO_PCM_ALSA;
	dev->fd      = -1;
	dev->open    = audio_open;
	dev->close   = audio_close;
	dev->write   = audio_write;
	dev->mix_set = mixer_set_level;
	dev->mix_get = mixer_get_level;
	dev->exit    = alsa_exit;
	
	NOTICE("ALSA Initilize OK\n");
	return 0;
}