コード例 #1
0
ファイル: alsa_qsa.c プロジェクト: DSkywalk/RetroArch
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;
}
コード例 #2
0
ファイル: audio_alsa.c プロジェクト: kichikuou/xsystem35-nacl
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;
}
コード例 #3
0
ファイル: ao_alsa5.c プロジェクト: DanielGit/Intrisit8000
/*
    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;
}
コード例 #4
0
ファイル: audio_alsa.c プロジェクト: kichikuou/xsystem35-nacl
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;
}
コード例 #5
0
ファイル: ao_alsa5.c プロジェクト: DanielGit/Intrisit8000
/* 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;
    }
}
コード例 #6
0
ファイル: ao_alsa5.c プロジェクト: DanielGit/Intrisit8000
/* 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;
    }
}
コード例 #7
0
ファイル: alsa_qsa.c プロジェクト: DSkywalk/RetroArch
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(&params, 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, &params)) < 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;
}
コード例 #8
0
ファイル: pcm_qsa.c プロジェクト: BaJIeK/brltty
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;
}
コード例 #9
0
ファイル: alsapmo.cpp プロジェクト: mayhem/freeamp
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();
   }
}
コード例 #10
0
ファイル: alsapmo.cpp プロジェクト: mayhem/freeamp
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(&params, 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, &params);
    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;
}
コード例 #11
0
ファイル: ao_alsa5.c プロジェクト: DanielGit/Intrisit8000
/*
    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;
}
コード例 #12
0
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;
}
コード例 #13
0
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(&param, 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, &param);

	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;
}