static int check_pcm_status(void *data, int channel_type) { snd_pcm_channel_status_t status; alsa_t *alsa = (alsa_t*)data; int ret = EOK; memset(&status, 0, sizeof (status)); status.channel = channel_type; if ((ret = snd_pcm_channel_status(alsa->pcm, &status)) == 0) { if (status.status == SND_PCM_STATUS_UNSECURE) { RARCH_ERR("check_pcm_status got SND_PCM_STATUS_UNSECURE, aborting playback\n"); ret = -EPROTO; } else if (status.status == SND_PCM_STATUS_UNDERRUN) { RARCH_LOG("check_pcm_status: SNDP_CM_STATUS_UNDERRUN.\n"); if ((ret = snd_pcm_channel_prepare(alsa->pcm, channel_type)) < 0) { RARCH_ERR("Invalid state detected for underrun on snd_pcm_channel_prepare: %s\n", snd_strerror(ret)); ret = -EPROTO; } } else if (status.status == SND_PCM_STATUS_OVERRUN) { RARCH_LOG("check_pcm_status: SNDP_CM_STATUS_OVERRUN.\n"); if ((ret = snd_pcm_channel_prepare(alsa->pcm, channel_type)) < 0) { RARCH_ERR("Invalid state detected for overrun on snd_pcm_channel_prepare: %s\n", snd_strerror(ret)); ret = -EPROTO; } } else if (status.status == SND_PCM_STATUS_CHANGE) { RARCH_LOG("check_pcm_status: SNDP_CM_STATUS_CHANGE.\n"); if ((ret = snd_pcm_channel_prepare(alsa->pcm, channel_type)) < 0) { RARCH_ERR("Invalid state detected for change on snd_pcm_channel_prepare: %s\n", snd_strerror(ret)); ret = -EPROTO; } } } else { RARCH_ERR("check_pcm_status failed: %s\n", snd_strerror(ret)); if (ret == -ESRCH) ret = -EBADF; } return ret; }
static int audio_write(audiodevice_t *dev, unsigned char *buf, int cnt) { audio_alsa05_t *alsa = (audio_alsa05_t *)dev->data_pcm; snd_pcm_channel_status_t st; int ret; if (alsa->pcm_handle == NULL) return NG; if (cnt == 0) return 0; if (cnt < dev->buf.len) { memset(buf + cnt, alsa->silence, dev->buf.len - cnt); } memset(&st, 0, sizeof(st)); if (0 > (ret = snd_pcm_channel_status(alsa->pcm_handle, &st))) { WARNING("cannot get status %s\n", snd_strerror(ret)); return 0; } if (st.status != SND_PCM_STATUS_RUNNING && st.status != SND_PCM_STATUS_PREPARED) { snd_pcm_channel_prepare(alsa->pcm_handle, SND_PCM_CHANNEL_PLAYBACK); } ret = snd_pcm_write(alsa->pcm_handle, buf, dev->buf.len); if (ret < 0) { WARNING("write %s\n", snd_strerror(ret)); } return dev->buf.len; }
/* plays 'len' bytes of 'data' returns: number of bytes played */ static int play(void* data, int len, int flags) { int got_len; if (!len) return 0; if ((got_len = snd_pcm_write(alsa_handler, data, len)) < 0) { if (got_len == -EPIPE) /* underrun? */ { mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_Underrun); if ((got_len = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) { mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_PlaybackPrepareError, snd_strerror(got_len)); return 0; } if ((got_len = snd_pcm_write(alsa_handler, data, len)) < 0) { mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_WriteErrorAfterReset, snd_strerror(got_len)); return 0; } return got_len; /* 2nd write was ok */ } mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_OutPutError, snd_strerror(got_len)); return 0; } return got_len; }
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; }
/* resume playing, after audio_pause() */ static void audio_resume(void) { int err; if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) { mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_ResumePrepareError, snd_strerror(err)); return; } }
/* stop playing and empty buffers (for seeking/pause) */ static void reset(void) { int err; if ((err = snd_pcm_playback_drain(alsa_handler)) < 0) { mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_ResetDrainError, snd_strerror(err)); return; } if ((err = snd_pcm_channel_flush(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) { mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_ResetFlushError, snd_strerror(err)); return; } if ((err = snd_pcm_channel_prepare(alsa_handler, SND_PCM_CHANNEL_PLAYBACK)) < 0) { mp_msg(MSGT_AO, MSGL_ERR, MSGTR_AO_ALSA5_ResetChanPrepareError, snd_strerror(err)); return; } }
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; }
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; }
void AlsaPMO::WorkerThread(void) { void *pBuffer; Error eErr; int iRet = -1; Event *pEvent; snd_pcm_channel_status_t ainfo; // Don't do anything until resume is called. m_pPauseSem->Wait(); // Sleep for a pre buffer period PreBuffer(); // The following should be abstracted out into the general thread // classes: #ifdef __linux__ struct sched_param sParam; sParam.sched_priority = sched_get_priority_max(SCHED_OTHER); pthread_setschedparam(pthread_self(), SCHED_OTHER, &sParam); #endif ainfo.channel = SND_PCM_CHANNEL_PLAYBACK; for(; !m_bExit;) { if (m_bPause) { m_pPauseSem->Wait(); continue; } // Loop until we get an Init event from the LMC if (!m_properlyInitialized) { pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent(); if (pEvent == NULL) { m_pLmc->Wake(); WasteTime(); continue; } if (pEvent->Type() == PMO_Init) { if (IsError(Init(((PMOInitEvent *)pEvent)->GetInfo()))) { delete pEvent; break; } } delete pEvent; continue; } // Set up reading a block from the buffer. If not enough bytes are // available, sleep for a little while and try again. for(;;) { eErr = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, m_iDataSize); if (eErr == kError_EndOfStream || eErr == kError_Interrupt) break; if (eErr == kError_NoDataAvail) { m_pLmc->Wake(); CheckForBufferUp(); WasteTime(); continue; } // Is there an event pending that we need to take care of // before we play this block of samples? if (eErr == kError_EventPending) { pEvent = ((EventBuffer *)m_pInputBuffer)->PeekEvent(); if (pEvent == NULL) continue; if (pEvent->Type() == PMO_Quit && ((EventBuffer *)m_pInputBuffer)->GetNumBytesInBuffer() > 0) { if (WaitForDrain()) { Reset(true); m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting)); return; } continue; } pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent(); if (pEvent->Type() == PMO_Init) Init(((PMOInitEvent *)pEvent)->GetInfo()); if (pEvent->Type() == PMO_Reset) Reset(false); if (pEvent->Type() == PMO_Info) HandleTimeInfoEvent((PMOTimeInfoEvent *)pEvent); if (pEvent->Type() == PMO_Quit) { delete pEvent; m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting)); return; } delete pEvent; continue; } if (IsError(eErr)) { ReportError("Internal error occured."); m_pContext->log->Error("Cannot read from buffer in PMO " "worker tread: %d\n", eErr); break; } break; } // Now write the block to the audio device. If the block doesn't // all fit, pause and loop until the entire block has been played. // This loop could be written using non-blocking io... for(;!m_bExit && !m_bPause;) { iRet = snd_pcm_write(m_handle,pBuffer,m_iDataSize); if (iRet == -EAGAIN) { CheckForBufferUp(); WasteTime(); continue; } if (iRet == -EIO) { snd_pcm_channel_prepare(m_handle, SND_PCM_CHANNEL_PLAYBACK); continue; } break; } if (m_bExit) { m_pInputBuffer->EndRead(0); return; } if (m_bPause) { if (iRet == -EAGAIN) m_pInputBuffer->EndRead(0); else { m_pInputBuffer->EndRead(iRet); UpdateBufferStatus(); } continue; } if (iRet < 0) { m_pInputBuffer->EndRead(0); ReportError("Could not write sound data to the soundcard."); m_pContext->log->Error("Failed to write to the soundcard: %s\n", strerror(errno)); break; } m_pInputBuffer->EndRead(iRet); m_pLmc->Wake(); UpdateBufferStatus(); } }
Error AlsaPMO::Init(OutputInfo* info) { int err; snd_pcm_channel_params_t params; m_properlyInitialized = false; if (!info) { info = myInfo; } else { // got info, so this is the beginning... m_iDataSize = info->max_buffer_size; err=snd_pcm_open(&m_handle, m_iCard, m_iDevice, SND_PCM_OPEN_PLAYBACK); if (err < 0) { ReportError("Audio device is busy. Please make sure that " "another program is not using the device."); return (Error)pmoError_DeviceOpenFailed; } snd_pcm_nonblock_mode(m_handle, 1); } // configure the device: m_channels=info->number_of_channels; m_rate=info->samples_per_second; memset(¶ms, 0, sizeof(params)); params.format.format = SND_PCM_SFMT_S16_LE; params.format.interleave = 1; params.format.voices = m_channels; params.format.rate = info->samples_per_second; params.channel = SND_PCM_CHANNEL_PLAYBACK; params.mode = SND_PCM_MODE_BLOCK; params.start_mode = SND_PCM_START_DATA; params.stop_mode = SND_PCM_STOP_STOP; params.buf.block.frag_size = m_iDataSize; params.buf.block.frags_max = 32; params.buf.block.frags_min = 1; err = snd_pcm_channel_params(m_handle, ¶ms); if (err < 0) { ReportError("Cannot initialized audio device."); return (Error)pmoError_DeviceOpenFailed; } err = snd_pcm_channel_prepare(m_handle, SND_PCM_CHANNEL_PLAYBACK); if (err < 0) { ReportError("Cannot initialized audio device."); return (Error)pmoError_DeviceOpenFailed; } memcpy(myInfo, info, sizeof(OutputInfo)); snd_pcm_channel_setup_t aInfo; aInfo.channel = SND_PCM_CHANNEL_PLAYBACK; err = snd_pcm_channel_setup(m_handle,&aInfo); if (err < 0) { ReportError("Cannot initialized audio device."); return (Error)pmoError_DeviceOpenFailed; } m_iOutputBufferSize = aInfo.buf.block.frag_size * aInfo.buf.block.frags; m_iBytesPerSample = info->number_of_channels * (info->bits_per_sample / 8); m_properlyInitialized = true; return kError_NoErr; }
/* 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; }
static gboolean alsa_open (void *dp) { alsa_driver * const d = dp; int mf, err; snd_pcm_format_t pf; // snd_pcm_channel_info_t pcm_info; snd_pcm_channel_params_t pp; snd_pcm_channel_setup_t setup; snd_pcm_channel_flush(d->soundfd, SND_PCM_CHANNEL_PLAYBACK); memset(&pp, 0, sizeof(pp)); err = snd_pcm_open(&(d->soundfd), d->card_number, d->device_number, SND_PCM_OPEN_PLAYBACK); if (err != 0) { char buf[256]; g_sprintf(buf, _("Couldn't open ALSA device for sound output (card:%d, device:%d):\n%s"), d->card_number, d->device_number, snd_strerror(err)); error_error(buf); goto out; } // --- // Set non-blocking mode. // --- // snd_pcm_nonblock_mode(d->soundfd, 1); d->outtime = 0; d->bits = 0; mf = 0; // -- // Set channel parameters // -- 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_ROLLOVER; // --- // Select audio format // --- memset(&pf, 0, sizeof(pf)); pf.interleave = 1; if (d->p_resolution == 16) { pf.format = SND_PCM_SFMT_S16_LE; d->bits = 16; mf = ST_MIXER_FORMAT_S16_LE; } else { pf.format = SND_PCM_SFMT_U8; d->bits = 8; mf = ST_MIXER_FORMAT_S8; } pf.rate = d->p_mixfreq; d->playrate = d->p_mixfreq; if(d->p_channels == 2) { d->stereo = 1; pf.voices = d->p_channels; mf |= ST_MIXER_FORMAT_STEREO; } else { pf.voices = d->p_channels; d->stereo = 0; } d->mf = mf; memcpy(&pp.format, &pf, sizeof(pf)); // pp.buf.block.frag_size = d->p_fragsize * pf.voices * (d->bits / 8); pp.buf.block.frag_size = d->p_fragsize; pp.buf.block.frags_max = -1; pp.buf.block.frags_min = 1; err = snd_pcm_channel_params(d->soundfd, &pp); if (err < 0) { error_error(_("Required output-channel parameters not supported.\n")); goto out; } if (snd_pcm_channel_prepare(d->soundfd, SND_PCM_CHANNEL_PLAYBACK) < 0) { error_error(_("Unable to prepare ALSA channel.\n")); goto out; } // --- // Get buffering parameters // --- memset(&setup, 0, sizeof(setup)); setup.mode = SND_PCM_MODE_BLOCK; setup.channel = SND_PCM_CHANNEL_PLAYBACK; err = snd_pcm_channel_setup(d->soundfd, &setup); if (err < 0) { error_error(_("Alsa setup error.\n")); goto out; } // snd_pcm_channel_status(d->soundfd, &pbstat); // d->fragsize = pbstat.fragment_size; d->numfrags = setup.buf.block.frags; d->fragsize = setup.buf.block.frag_size; /* fprintf(stderr, "Numfrags: %d\n", d->numfrags); fprintf(stderr, "Fragsize: %d\n", d->fragsize); */ d->sndbuf = calloc(1, d->fragsize); if(d->stereo == 1) { d->fragsize /= 2; } if(d->bits == 16) { d->fragsize /= 2; } d->polltag = audio_poll_add(snd_pcm_file_descriptor(d->soundfd, SND_PCM_CHANNEL_PLAYBACK), GDK_INPUT_WRITE, alsa_poll_ready_playing, d); /* d->firstpoll = TRUE; */ d->firstpoll = TRUE; d->playtime = 0; return TRUE; out: alsa_release(dp); return FALSE; }
int ao_plugin_open(ao_device *device, ao_sample_format *format) { ao_alsa_internal *internal = (ao_alsa_internal *) device->internal; snd_pcm_channel_params_t param; int err; memset(¶m, 0, sizeof(param)); param.channel = SND_PCM_CHANNEL_PLAYBACK; param.mode = SND_PCM_MODE_BLOCK; param.format.interleave = 1; switch (format->bits) { case 8 : param.format.format = SND_PCM_SFMT_S8; break; case 16 : param.format.format = device->client_byte_format == AO_FMT_BIG ? SND_PCM_SFMT_S16_BE : SND_PCM_SFMT_S16_LE; device->driver_byte_format = device->client_byte_format; break; default : return 0; } if (format->channels == 1 || format->channels == 2) param.format.voices = format->channels; else return 0; /* Finish filling in the parameter structure */ param.format.rate = format->rate; param.start_mode = SND_PCM_START_FULL; param.stop_mode = SND_PCM_STOP_STOP; param.buf.block.frag_size = internal->buf_size; param.buf.block.frags_min = 1; param.buf.block.frags_max = 8; internal->buf = malloc(internal->buf_size); internal->buf_end = 0; if (internal->buf == NULL) return 0; /* Could not alloc swap buffer */ /* Open the ALSA device */ err = snd_pcm_open(&(internal->pcm_handle), internal->card, internal->dev, SND_PCM_OPEN_PLAYBACK | SND_PCM_OPEN_NONBLOCK); if (err < 0) { free(internal->buf); return 0; } err = snd_pcm_channel_params(internal->pcm_handle, ¶m); if (err < 0) { snd_pcm_close(internal->pcm_handle); free(internal->buf); return 0; } snd_pcm_nonblock_mode(internal->pcm_handle, 0); snd_pcm_channel_prepare(internal->pcm_handle, SND_PCM_CHANNEL_PLAYBACK); return 1; }