static int audio_open(audiodevice_t *dev, chanfmt_t fmt) { audio_alsa05_t *alsa = (audio_alsa05_t *)dev->data_pcm; snd_pcm_channel_params_t p; snd_pcm_channel_setup_t s; if (0 > snd_pcm_open(&alsa->pcm_handle, alsa->card, alsa->pcm_dev, SND_PCM_OPEN_PLAYBACK)) { WARNING("Opening audio device %d failed\n", alsa->pcm_dev); goto _err_exit; } memset(&alsa->info, 0, sizeof(snd_pcm_channel_info_t)); if (0 > snd_pcm_channel_info(alsa->pcm_handle, &alsa->info)) { WARNING("param get failed\n"); goto _err_exit; } memset(&p, 0, sizeof(p)); p.mode = SND_PCM_MODE_BLOCK; p.start_mode = SND_PCM_START_DATA; p.channel = SND_PCM_CHANNEL_PLAYBACK; p.stop_mode = SND_PCM_STOP_STOP; p.buf.block.frag_size = 1536; p.buf.block.frags_max = 6; p.buf.block.frags_min = 1; p.format.rate = fmt.rate; p.format.format = fmt.bit == 8 ? SND_PCM_SFMT_U8 : SND_PCM_SFMT_S16; p.format.voices = fmt.ch; p.format.interleave = 1; alsa->silence = fmt.bit == 8 ? 0x80 : 0; if (0 > snd_pcm_channel_params(alsa->pcm_handle, &p)) { WARNING("Unable to set channel params\n"); goto _err_exit; } if (0 > snd_pcm_channel_prepare(alsa->pcm_handle, SND_PCM_CHANNEL_PLAYBACK)) { WARNING("Unable to prepare channel\n"); goto _err_exit; } memset(&s, 0, sizeof(s)); s.mode = SND_PCM_MODE_BLOCK; s.channel = SND_PCM_CHANNEL_PLAYBACK; if (0 > snd_pcm_channel_setup(alsa->pcm_handle, &s)) { WARNING("Unable to obtain setup\n"); goto _err_exit; } dev->buf.len = s.buf.block.frag_size; dev->fd = snd_pcm_file_descriptor(alsa->pcm_handle, SND_PCM_CHANNEL_PLAYBACK); return OK; _err_exit: dev->fd = -1; return NG; }
int snd_pcm_generic_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) { snd_pcm_generic_t *generic = pcm->private_data; if (pcm->mmap_shadow) { /* No own buffer is required - the plugin won't change * the data on the buffer, or do safely on-the-place * conversion */ return snd_pcm_channel_info(generic->slave, info); } else { /* Allocate own buffer */ return snd_pcm_channel_info_shm(pcm, info, -1); } }
static int snd_pcm_ioctl_channel_info_compat(struct snd_pcm_substream *substream, struct snd_pcm_channel_info32 __user *src) { struct snd_pcm_channel_info info; int err; if (get_user(info.channel, &src->channel) || get_user(info.offset, &src->offset) || get_user(info.first, &src->first) || get_user(info.step, &src->step)) return -EFAULT; err = snd_pcm_channel_info(substream, &info); if (err < 0) return err; if (put_user(info.channel, &src->channel) || put_user(info.offset, &src->offset) || put_user(info.first, &src->first) || put_user(info.step, &src->step)) return -EFAULT; return err; }
static void *alsa_qsa_init(const char *device, unsigned rate, unsigned latency, unsigned block_frames, unsigned *new_rate) { int err, card, dev, i; snd_pcm_channel_info_t pi; snd_pcm_channel_params_t params = {0}; snd_pcm_channel_setup_t setup = {0}; alsa_t *alsa = (alsa_t*)calloc(1, sizeof(alsa_t)); if (!alsa) return NULL; (void)device; (void)rate; (void)latency; if ((err = snd_pcm_open_preferred(&alsa->pcm, &card, &dev, SND_PCM_OPEN_PLAYBACK)) < 0) { RARCH_ERR("[ALSA QSA]: Audio open error: %s\n", snd_strerror(err)); goto error; } if((err = snd_pcm_nonblock_mode(alsa->pcm, 1)) < 0) { RARCH_ERR("[ALSA QSA]: Can't set blocking mode: %s\n", snd_strerror(err)); goto error; } memset(&pi, 0, sizeof(pi)); pi.channel = SND_PCM_CHANNEL_PLAYBACK; if ((err = snd_pcm_channel_info(alsa->pcm, &pi)) < 0) { RARCH_ERR("[ALSA QSA]: snd_pcm_channel_info failed: %s\n", snd_strerror(err)); goto error; } memset(¶ms, 0, sizeof(params)); params.channel = SND_PCM_CHANNEL_PLAYBACK; params.mode = SND_PCM_MODE_BLOCK; params.format.interleave = 1; params.format.format = SND_PCM_SFMT_S16_LE; params.format.rate = DEFAULT_RATE; params.format.voices = 2; params.start_mode = SND_PCM_START_FULL; params.stop_mode = SND_PCM_STOP_STOP; params.buf.block.frag_size = pi.max_fragment_size; params.buf.block.frags_min = 2; params.buf.block.frags_max = 8; RARCH_LOG("Fragment size: %d\n", params.buf.block.frag_size); RARCH_LOG("Min Fragment size: %d\n", params.buf.block.frags_min); RARCH_LOG("Max Fragment size: %d\n", params.buf.block.frags_max); if ((err = snd_pcm_channel_params(alsa->pcm, ¶ms)) < 0) { RARCH_ERR("[ALSA QSA]: Channel Parameter Error: %s\n", snd_strerror(err)); goto error; } setup.channel = SND_PCM_CHANNEL_PLAYBACK; if ((err = snd_pcm_channel_setup(alsa->pcm, &setup)) < 0) { RARCH_ERR("[ALSA QSA]: Channel Parameter Read Back Error: %s\n", snd_strerror(err)); goto error; } if (block_frames) alsa->buf_size = block_frames * 4; else alsa->buf_size = next_pow2(32 * latency); RARCH_LOG("[ALSA QSA]: buffer size: %u bytes\n", alsa->buf_size); alsa->buf_count = (latency * 4 * rate + 500) / 1000; alsa->buf_count = (alsa->buf_count + alsa->buf_size / 2) / alsa->buf_size; if ((err = snd_pcm_channel_prepare(alsa->pcm, SND_PCM_CHANNEL_PLAYBACK)) < 0) { RARCH_ERR("[ALSA QSA]: Channel Prepare Error: %s\n", snd_strerror(err)); goto error; } alsa->buffer = (uint8_t**)calloc(sizeof(uint8_t*), alsa->buf_count); if (!alsa->buffer) goto error; alsa->buffer_chunk = (uint8_t*)calloc(alsa->buf_count, alsa->buf_size); if (!alsa->buffer_chunk) goto error; for (i = 0; i < alsa->buf_count; i++) alsa->buffer[i] = alsa->buffer_chunk + i * alsa->buf_size; alsa->has_float = false; alsa->can_pause = true; RARCH_LOG("[ALSA QSA]: Can pause: %s.\n", alsa->can_pause ? "yes" : "no"); return alsa; error: return (void*)-1; }
int snd_pcm_mmap(snd_pcm_t *pcm) { int err; unsigned int c; assert(pcm); if (CHECK_SANITY(! pcm->setup)) { SNDMSG("PCM not set up"); return -EIO; } if (CHECK_SANITY(pcm->mmap_channels || pcm->running_areas)) { SNDMSG("Already mmapped"); return -EBUSY; } err = pcm->ops->mmap(pcm); if (err < 0) return err; if (pcm->mmap_shadow) return 0; pcm->mmap_channels = calloc(pcm->channels, sizeof(pcm->mmap_channels[0])); if (!pcm->mmap_channels) return -ENOMEM; pcm->running_areas = calloc(pcm->channels, sizeof(pcm->running_areas[0])); if (!pcm->running_areas) { free(pcm->mmap_channels); pcm->mmap_channels = NULL; return -ENOMEM; } for (c = 0; c < pcm->channels; ++c) { snd_pcm_channel_info_t *i = &pcm->mmap_channels[c]; i->channel = c; err = snd_pcm_channel_info(pcm, i); if (err < 0) return err; } for (c = 0; c < pcm->channels; ++c) { snd_pcm_channel_info_t *i = &pcm->mmap_channels[c]; snd_pcm_channel_area_t *a = &pcm->running_areas[c]; char *ptr; size_t size; unsigned int c1; if (i->addr) { a->addr = i->addr; a->first = i->first; a->step = i->step; continue; } size = i->first + i->step * (pcm->buffer_size - 1) + pcm->sample_bits; for (c1 = c + 1; c1 < pcm->channels; ++c1) { snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1]; size_t s; if (i1->type != i->type) continue; switch (i1->type) { case SND_PCM_AREA_MMAP: if (i1->u.mmap.fd != i->u.mmap.fd || i1->u.mmap.offset != i->u.mmap.offset) continue; break; case SND_PCM_AREA_SHM: if (i1->u.shm.shmid != i->u.shm.shmid) continue; break; case SND_PCM_AREA_LOCAL: break; default: assert(0); } s = i1->first + i1->step * (pcm->buffer_size - 1) + pcm->sample_bits; if (s > size) size = s; } size = (size + 7) / 8; size = page_align(size); switch (i->type) { case SND_PCM_AREA_MMAP: ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, i->u.mmap.fd, i->u.mmap.offset); if (ptr == MAP_FAILED) { SYSERR("mmap failed"); return -errno; } i->addr = ptr; break; case SND_PCM_AREA_SHM: if (i->u.shm.shmid < 0) { int id; /* FIXME: safer permission? */ id = shmget(IPC_PRIVATE, size, 0666); if (id < 0) { SYSERR("shmget failed"); return -errno; } i->u.shm.shmid = id; ptr = shmat(i->u.shm.shmid, 0, 0); if (ptr == (void *) -1) { SYSERR("shmat failed"); return -errno; } /* automatically remove segment if not used */ if (shmctl(id, IPC_RMID, NULL) < 0){ SYSERR("shmctl mark remove failed"); return -errno; } i->u.shm.area = snd_shm_area_create(id, ptr); if (i->u.shm.area == NULL) { SYSERR("snd_shm_area_create failed"); return -ENOMEM; } if (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED || pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED) { unsigned int c1; for (c1 = c + 1; c1 < pcm->channels; c1++) { snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1]; if (i1->u.shm.shmid < 0) { i1->u.shm.shmid = id; i1->u.shm.area = snd_shm_area_share(i->u.shm.area); } } } } else { ptr = shmat(i->u.shm.shmid, 0, 0); if (ptr == (void*) -1) { SYSERR("shmat failed"); return -errno; } } i->addr = ptr; break; case SND_PCM_AREA_LOCAL: ptr = malloc(size); if (ptr == NULL) { SYSERR("malloc failed"); return -errno; } i->addr = ptr; break; default: assert(0); } for (c1 = c + 1; c1 < pcm->channels; ++c1) { snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1]; if (i1->type != i->type) continue; switch (i1->type) { case SND_PCM_AREA_MMAP: if (i1->u.mmap.fd != i->u.mmap.fd || i1->u.mmap.offset != i->u.mmap.offset) continue; break; case SND_PCM_AREA_SHM: if (i1->u.shm.shmid != i->u.shm.shmid) continue; /* follow thru */ case SND_PCM_AREA_LOCAL: if (pcm->access != SND_PCM_ACCESS_MMAP_INTERLEAVED && pcm->access != SND_PCM_ACCESS_RW_INTERLEAVED) continue; break; default: assert(0); } i1->addr = i->addr; } a->addr = i->addr; a->first = i->first; a->step = i->step; } return 0; }
PcmDevice * openPcmDevice (int errorLevel, const char *device) { PcmDevice *pcm; if ((pcm = malloc(sizeof(*pcm)))) { int code; if (*device) { { int ok = 0; long number; char *end; const char *component = device; number = strtol(component, &end, 0); if ((*end && (*end != ':')) || (number < 0) || (number > 0XFF)) { logMessage(errorLevel, "Invalid QSA card number: %s", device); } else if (end == component) { logMessage(errorLevel, "Missing QSA card number: %s", device); } else { pcm->card = number; if (*end) { component = end + 1; number = strtol(component, &end, 0); if (*end || (number < 0) || (number > 0XFF)) { logMessage(errorLevel, "Invalid QSA device number: %s", device); } else if (end == component) { logMessage(errorLevel, "Missing QSA device number: %s", device); } else { pcm->device = number; ok = 1; } } else { pcm->device = 0; ok = 1; } } if (!ok) goto openError; } if ((code = snd_pcm_open(&pcm->handle, pcm->card, pcm->device, SND_PCM_OPEN_PLAYBACK)) < 0) { logPcmError(errorLevel, "open", code); goto openError; } } else if ((code = snd_pcm_open_preferred(&pcm->handle, &pcm->card, &pcm->device, SND_PCM_OPEN_PLAYBACK)) < 0) { logPcmError(errorLevel, "preferred open", code); goto openError; } logMessage(LOG_DEBUG, "QSA PCM device opened: %d:%d", pcm->card, pcm->device); { snd_pcm_channel_info_t info; info.channel = SND_PCM_CHANNEL_PLAYBACK; if ((code = snd_pcm_channel_info(pcm->handle, &info)) >= 0) { logMessage(LOG_DEBUG, "QSA PCM Info: Frag=%d-%d Rate=%d-%d Chan=%d-%d", info.min_fragment_size, info.max_fragment_size, info.min_rate, info.max_rate, info.min_voices, info.max_voices); memset(&pcm->parameters, 0, sizeof(pcm->parameters)); pcm->parameters.channel = info.channel; pcm->parameters.start_mode = SND_PCM_START_DATA; pcm->parameters.stop_mode = SND_PCM_STOP_ROLLOVER; switch (pcm->parameters.mode = SND_PCM_MODE_BLOCK) { case SND_PCM_MODE_BLOCK: pcm->parameters.buf.block.frag_size = MIN(MAX(0X400, info.min_fragment_size), info.max_fragment_size); pcm->parameters.buf.block.frags_min = 1; pcm->parameters.buf.block.frags_max = 0X40; break; default: logMessage(LOG_WARNING, "Unsupported QSA PCM mode: %d", pcm->parameters.mode); goto openError; } pcm->parameters.format.interleave = 1; pcm->parameters.format.rate = info.max_rate; pcm->parameters.format.voices = MIN(MAX(1, info.min_voices), info.max_voices); pcm->parameters.format.format = SND_PCM_SFMT_S16; if (reconfigurePcmChannel(pcm, errorLevel)) { if ((code = snd_pcm_channel_prepare(pcm->handle, pcm->parameters.channel)) >= 0) { return pcm; } else { logPcmError(errorLevel, "prepare channel", code); } } } else { logPcmError(errorLevel, "get channel information", code); } } openError: free(pcm); } else { logSystemError("PCM device allocation"); } return NULL; }
/* 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(¶ms, 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, ¶ms)) < 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; }
qboolean SNDDMA_Init (void) { int rc = 0, i; char *err_msg = ""; int rate = -1, format = -1, bps, stereo = -1, frag_size; unsigned int mask; mask = snd_cards_mask (); if (!mask) { Con_Printf ("No sound cards detected\n"); return 0; } if ((i = COM_CheckParm ("-sndcard")) != 0) { card = atoi (com_argv[i + 1]); } if ((i = COM_CheckParm ("-snddev")) != 0) { dev = atoi (com_argv[i + 1]); } if ((i = COM_CheckParm ("-sndbits")) != 0) { i = atoi (com_argv[i + 1]); if (i == 16) { format = SND_PCM_SFMT_S16_LE; } else if (i == 8) { format = SND_PCM_SFMT_U8; } else { Con_Printf ("Error: invalid sample bits: %d\n", i); return 0; } } if ((i = COM_CheckParm ("-sndspeed")) != 0) { rate = atoi (com_argv[i + 1]); if (rate != 44100 && rate != 22050 && rate != 11025) { Con_Printf ("Error: invalid sample rate: %d\n", rate); return 0; } } if ((i = COM_CheckParm ("-sndmono")) != 0) { stereo = 0; } if (card == -1) { for (card = 0; card < SND_CARDS; card++) { if (!(mask & (1 << card))) continue; rc = check_card (card); if (rc < 0) return 0; if (!rc) goto dev_openned; } } else { if (dev == -1) { rc = check_card (card); if (rc < 0) return 0; if (!rc) goto dev_openned; } else { if ((rc = snd_pcm_open (&pcm_handle, card, dev, SND_PCM_OPEN_PLAYBACK | SND_PCM_OPEN_NONBLOCK)) < 0) { Con_Printf ("Error: audio open error: %s\n", snd_strerror (rc)); return 0; } goto dev_openned; } } Con_Printf ("Error: audio open error: %s\n", snd_strerror (rc)); return 0; dev_openned: Con_Printf ("Using card %d, device %d.\n", card, dev); memset (&cinfo, 0, sizeof (cinfo)); cinfo.channel = SND_PCM_CHANNEL_PLAYBACK; snd_pcm_channel_info (pcm_handle, &cinfo); Con_Printf ("%08x %08x %08x\n", cinfo.flags, cinfo.formats, cinfo.rates); if ((rate == -1 || rate == 44100) && cinfo.rates & SND_PCM_RATE_44100) { rate = 44100; frag_size = 512; /* assuming stereo 8 bit */ } else if ((rate == -1 || rate == 22050) && cinfo.rates & SND_PCM_RATE_22050) { rate = 22050; frag_size = 256; /* assuming stereo 8 bit */ } else if ((rate == -1 || rate == 11025) && cinfo.rates & SND_PCM_RATE_11025) { rate = 11025; frag_size = 128; /* assuming stereo 8 bit */ } else { Con_Printf ("ALSA: desired rates not supported\n"); goto error_2; } if ((format == -1 || format == SND_PCM_SFMT_S16_LE) && cinfo.formats & SND_PCM_FMT_S16_LE) { format = SND_PCM_SFMT_S16_LE; bps = 16; frag_size *= 2; } else if ((format == -1 || format == SND_PCM_SFMT_U8) && cinfo.formats & SND_PCM_FMT_U8) { format = SND_PCM_SFMT_U8; bps = 8; } else { Con_Printf ("ALSA: desired formats not supported\n"); goto error_2; } if (stereo && cinfo.max_voices >= 2) { stereo = 1; } else { stereo = 0; frag_size /= 2; } // err_msg="audio flush"; // if ((rc=snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK))<0) // goto error; err_msg = "audio munmap"; if ((rc = snd_pcm_munmap (pcm_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0) goto error; memset (¶ms, 0, sizeof (params)); params.channel = SND_PCM_CHANNEL_PLAYBACK; params.mode = SND_PCM_MODE_BLOCK; params.format.interleave = 1; params.format.format = format; params.format.rate = rate; params.format.voices = stereo + 1; params.start_mode = SND_PCM_START_GO; params.stop_mode = SND_PCM_STOP_ROLLOVER; params.buf.block.frag_size = frag_size; params.buf.block.frags_min = 1; params.buf.block.frags_max = -1; // err_msg="audio flush"; // if ((rc=snd_pcm_channel_flush(pcm_handle, SND_PCM_CHANNEL_PLAYBACK))<0) // goto error; err_msg = "audio params"; if ((rc = snd_pcm_channel_params (pcm_handle, ¶ms)) < 0) goto error; err_msg = "audio mmap"; if ( (rc = snd_pcm_mmap (pcm_handle, SND_PCM_CHANNEL_PLAYBACK, &mmap_control, (void **) &mmap_data)) < 0) goto error; err_msg = "audio prepare"; if ((rc = snd_pcm_plugin_prepare (pcm_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0) goto error; memset (&setup, 0, sizeof (setup)); setup.mode = SND_PCM_MODE_BLOCK; setup.channel = SND_PCM_CHANNEL_PLAYBACK; err_msg = "audio setup"; if ((rc = snd_pcm_channel_setup (pcm_handle, &setup)) < 0) goto error; shm = &sn; memset ((dma_t *) shm, 0, sizeof (*shm)); shm->splitbuffer = 0; shm->channels = setup.format.voices; shm->submission_chunk = 128; // don't mix less than this # shm->samplepos = 0; // in mono samples shm->samplebits = setup.format.format == SND_PCM_SFMT_S16_LE ? 16 : 8; shm->samples = setup.buf.block.frags * setup.buf.block.frag_size / (shm->samplebits / 8); // mono // samples // in // buffer shm->speed = setup.format.rate; shm->buffer = (unsigned char *) mmap_data; Con_Printf ("%5d stereo\n", shm->channels - 1); Con_Printf ("%5d samples\n", shm->samples); Con_Printf ("%5d samplepos\n", shm->samplepos); Con_Printf ("%5d samplebits\n", shm->samplebits); Con_Printf ("%5d submission_chunk\n", shm->submission_chunk); Con_Printf ("%5d speed\n", shm->speed); Con_Printf ("0x%x dma buffer\n", (int) shm->buffer); Con_Printf ("%5d total_channels\n", total_channels); snd_inited = 1; return 1; error: Con_Printf ("Error: %s: %s\n", err_msg, snd_strerror (rc)); error_2: snd_pcm_close (pcm_handle); return 0; }
// Initialize audio and report back a few parameters of the channel int setupAudio( ) { int error; snd_pcm_channel_info_t pi; snd_pcm_channel_params_t pp; snd_pcm_channel_setup_t ps; //if ((error = snd_pcm_open_name (&playback_handle, "pcmPreferred", SND_PCM_OPEN_PLAYBACK)) < 0) { if ((error = snd_pcm_open_name (&playback_handle, "tones", SND_PCM_OPEN_PLAYBACK)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to open preferred audio driver\n"); return -error; } sample_handle = snd_pcm_file_descriptor( playback_handle, SND_PCM_CHANNEL_PLAYBACK ); if ((error = snd_pcm_plugin_set_disable (playback_handle, PLUGIN_DISABLE_MMAP)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to disable mmap\n"); snd_pcm_close(playback_handle); return -error; } if ((error = snd_pcm_plugin_set_enable (playback_handle, PLUGIN_ROUTING)) < 0) { slogf ( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "snd_pcm_plugin_set_enable failed: %s\n", snd_strerror (error)); snd_pcm_close(playback_handle); return -error; } // Find what sample rate and format to use memset( &pi, 0, sizeof(pi) ); pi.channel = SND_PCM_CHANNEL_PLAYBACK; if ((error = snd_pcm_channel_info (playback_handle, &pi)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to get plugin info\n"); snd_pcm_close(playback_handle); return -error; } // Initialize the playback channel memset(&pp, 0, sizeof(pp) ); pp.mode = SND_PCM_MODE_BLOCK; pp.channel = SND_PCM_CHANNEL_PLAYBACK; pp.start_mode = SND_PCM_START_FULL; pp.stop_mode = SND_PCM_STOP_STOP; pp.buf.block.frag_size = pi.max_fragment_size; pp.buf.block.frags_max = 3; pp.buf.block.frags_min = 1; pp.format.interleave = 1; pp.format.format = SND_PCM_SFMT_S16_LE; pp.format.rate = 48000; pp.format.voices = 2; memset( &ps, 0, sizeof( ps ) ); memset( &group, 0, sizeof( group ) ); ps.channel = SND_PCM_CHANNEL_PLAYBACK; ps.mixer_gid = &group.gid; //strcpy(pp.sw_mixer_subchn_name, "Wave playback channel"); strcpy(pp.sw_mixer_subchn_name, "voice_ringtone"); if ((error = snd_pcm_plugin_params( playback_handle, &pp)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to set plugin params\n"); snd_pcm_close(playback_handle); return -error; } if ((error = snd_pcm_plugin_prepare (playback_handle, SND_PCM_CHANNEL_PLAYBACK)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to set prepare plugin\n"); snd_pcm_close(playback_handle); return -error; } if ((error = snd_pcm_plugin_setup (playback_handle, &ps)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to setup plugin\n"); snd_pcm_close(playback_handle); return -error; } card = ps.mixer_card; device = ps.mixer_device; if( audioman_handle ) { if ((error = snd_pcm_set_audioman_handle (playback_handle, audioman_handle)) < 0) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to set audioman handle \n"); snd_pcm_close(playback_handle); return -error; } } sample_frequency = ps.format.rate; frag_samples = ps.buf.block.frag_size / 4; frame_size = ps.buf.block.frag_size; format = pp.format.format; /* // Only support 16-bit samples for now frag_buffer = malloc( ps.buf.block.frag_size * 2 ); if( frag_buffer == NULL ) { slogf( _SLOG_SETCODE(_SLOGC_AUDIO, 0), _SLOG_CRITICAL, "Unable to alloc frag buffer\n"); snd_pcm_close(playback_handle); return ENOMEM; } */ fprintf (stderr,"Playback Format %s card = %d\n", snd_pcm_get_format_name (ps.format.format),card); fprintf (stderr,"Playback preferred frame_size %d \n", pi.max_fragment_size); fprintf (stderr,"Playback frame_size %d \n", ps.buf.block.frag_size); fprintf (stderr,"Playback frame_samples %d \n", frag_samples); fprintf (stderr,"Playback Rate %d \n", ps.format.rate); if (group.gid.name[0] == 0) { fprintf (stderr,"Playback Mixer Pcm Group [%s] Not Set \n", group.gid.name); return -1; } fprintf (stderr, "Playback Mixer Pcm Group [%s]\n", group.gid.name); return EOK; }