Exemplo n.º 1
0
void COSSAudioSource::ProcessAudio(void)
{
#ifdef SNDCTL_DSP_GETERROR
  audio_errinfo errinfo;
  if (m_audioSrcFrameNumber == 0) {
    ioctl(m_audioDevice, SNDCTL_DSP_GETERROR, &errinfo);
  } else {
    ioctl(m_audioDevice, SNDCTL_DSP_GETERROR, &errinfo);
    if (errinfo.rec_overruns > 0) {
      debug_message("overrun error found in audio - adding "U64" samples",
		    SrcBytesToSamples(errinfo.rec_ptradjust));
      close(m_audioDevice);
      InitDevice();
      m_audioSrcSampleNumber = 0;
    }
  }
#endif

  if (m_audioSrcFrameNumber == 0) {
    // Pull the trigger and start the audio input
    int enablebits;
    ioctl(m_audioDevice, SNDCTL_DSP_GETTRIGGER, &enablebits);
    enablebits |= PCM_ENABLE_INPUT;
    ioctl(m_audioDevice, SNDCTL_DSP_SETTRIGGER, &enablebits);
  }

  // for efficiency, process 1 second before returning to check for commands
  for (int pass = 0; pass < m_maxPasses; pass++) {

    audio_buf_info info;
    int rc = ioctl(m_audioDevice, SNDCTL_DSP_GETISPACE, &info);
    Timestamp currentTime = GetTimestamp();

    if (rc<0) {
      error_message("Failed to query OSS GETISPACE");
      info.bytes = 0;
    }

    uint32_t bytesRead = read(m_audioDevice, m_pcmFrameBuffer, m_pcmFrameSize);
    if (bytesRead < m_pcmFrameSize) {
      debug_message("bad audio read");
      continue;
    }

    Timestamp timestamp;

    if (info.bytes == m_audioOssMaxBufferSize) {
      // means the audio buffer is full, and not capturing
      // we want to make the timestamp based on the previous one
      // When we hit this case, we start using the m_timestampOverflowArray
      // This will give us a timestamp for when the array is full.
      // 
      // In other words, if we have a full audio buffer (ie: it's not loading
      // any more), we start storing the current timestamp into the array.
      // This will let us "catch up", and have a somewhat accurate timestamp
      // when we loop around
      // 
      // wmay - I'm not convinced that this actually works - if the buffer
      // cleans up, we'll ignore m_timestampOverflowArray
      if (m_timestampOverflowArray != NULL && 
	  m_timestampOverflowArray[m_timestampOverflowArrayIndex] != 0) {
	timestamp = m_timestampOverflowArray[m_timestampOverflowArrayIndex];
      } else {
	timestamp = m_prevTimestamp + SrcSamplesToTicks(m_audioSrcSamplesPerFrame);
      }

      if (m_timestampOverflowArray != NULL)
	m_timestampOverflowArray[m_timestampOverflowArrayIndex] = currentTime;

      debug_message("audio buffer full !");

    } else {
      // buffer is not full - so, we make the timestamp based on the number
      // of bytes in the buffer that we read.
      timestamp = currentTime - SrcSamplesToTicks(SrcBytesToSamples(info.bytes));
      if (m_timestampOverflowArray != NULL)
	m_timestampOverflowArray[m_timestampOverflowArrayIndex] = 0;
    }

#ifdef DEBUG_TIMESTAMPS
    debug_message("info.bytes=%d t="U64" timestamp="U64" delta="U64,
                  info.bytes, currentTime, timestamp, timestamp - m_prevTimestamp);
#endif

    m_prevTimestamp = timestamp;
    if (m_timestampOverflowArray != NULL) {
      m_timestampOverflowArrayIndex = (m_timestampOverflowArrayIndex + 1) % 
	m_audioOssMaxBufferFrames;
    }

    ProcessAudioFrame(m_pcmFrameBuffer, m_pcmFrameSize, timestamp);

  }
}
Exemplo n.º 2
0
void CALSAAudioSource::ProcessAudio(void)
{
	int err;
	
  if (m_audioSrcFrameNumber == 0) {
  	// Start the device
    if ((err = snd_pcm_start(m_pcmHandle)) < 0) {
      error_message("Couldn't start the PCM device: %s", snd_strerror(err));
    }
  }
	
  snd_pcm_status_t *status;
  snd_pcm_status_alloca(&status);

  // for efficiency, process 1 second before returning to check for commands
  for (int pass = 0; pass < m_maxPasses && m_stop_thread == false; pass++) {

    u_int8_t*     pcmFrameBuffer;
    pcmFrameBuffer = (u_int8_t*)malloc(m_pcmFrameSize);

    // The alsa frames is not the same as the pcm frames used to feed the encoder
    // Calculate how many alsa frames is neccesary to read to fill one pcm frame
	  snd_pcm_uframes_t num_frames = m_pcmFrameSize / (m_audioSrcChannels * sizeof(u_int16_t));
	  
		// Check how many bytes there is to read in the buffer, it will be used to calculate timestamp
    snd_pcm_status(m_pcmHandle, status);
		unsigned long avail_bytes = snd_pcm_status_get_avail(status) * (m_audioSrcChannels * sizeof(u_int16_t));
    Timestamp currentTime = GetTimestamp();
    Timestamp timestamp;

    // Read num_frames frames from the PCM device
    // pointed to by pcm_handle to buffer capdata.
    // Returns the number of frames actually read.
    // TODO On certain alsa configurations, e.g. when using dsnoop with low sample rate, the period gets too small. What to do about that?
    snd_pcm_sframes_t framesRead;
    if((framesRead = snd_pcm_readi(m_pcmHandle, pcmFrameBuffer, num_frames)) == -EPIPE) {
      snd_pcm_prepare(m_pcmHandle);
      // Buffer Overrun. This means the audio buffer is full, and not capturing
      // we want to make the timestamp based on the previous one
      // When we hit this case, we start using the m_timestampOverflowArray
      // This will give us a timestamp for when the array is full.
      // 
      // In other words, if we have a full audio buffer (ie: it's not loading
      // any more), we start storing the current timestamp into the array.
      // This will let us "catch up", and have a somewhat accurate timestamp
      // when we loop around
      // 
      // wmay - I'm not convinced that this actually works - if the buffer
      // cleans up, we'll ignore m_timestampOverflowArray
      if (m_timestampOverflowArray != NULL && m_timestampOverflowArray[m_timestampOverflowArrayIndex] != 0) {
        timestamp = m_timestampOverflowArray[m_timestampOverflowArrayIndex];
      } else {
        timestamp = m_prevTimestamp + SrcSamplesToTicks(avail_bytes);
      }

      if (m_timestampOverflowArray != NULL)
        m_timestampOverflowArray[m_timestampOverflowArrayIndex] = currentTime;

      debug_message("audio buffer full !");
    } else {
      if (framesRead < (snd_pcm_sframes_t) num_frames) {
        error_message("Bad audio read. Expected %li frames, got %li", num_frames, framesRead);
        free(pcmFrameBuffer);
        continue;
      }

      // buffer is not full - so, we make the timestamp based on the number
      // of bytes in the buffer that we read.
      timestamp = currentTime - SrcSamplesToTicks(SrcBytesToSamples(avail_bytes));
      if (m_timestampOverflowArray != NULL)
        m_timestampOverflowArray[m_timestampOverflowArrayIndex] = 0;
    }
    //debug_message("alsa read");
#ifdef DEBUG_TIMESTAMPS
    debug_message("avail_bytes=%lu t="U64" timestamp="U64" delta="U64,
                  avail_bytes, currentTime, timestamp, timestamp - m_prevTimestamp);
#endif

    m_prevTimestamp = timestamp;
    if (m_timestampOverflowArray != NULL) {
      m_timestampOverflowArrayIndex = (m_timestampOverflowArrayIndex + 1) % m_audioMaxBufferFrames;
    }
#ifdef DEBUG_TIMESTAMPS
    debug_message("pcm forward "U64" %u", timestamp, m_pcmFrameSize);
#endif
    if (m_audioSrcFrameNumber == 0 && m_videoSource != NULL) {
      m_videoSource->RequestKeyFrame(timestamp);
    }
    m_audioSrcFrameNumber++;
    CMediaFrame *frame = new CMediaFrame(PCMAUDIOFRAME,
					 pcmFrameBuffer, 
					 m_pcmFrameSize, 
					 timestamp);
    ForwardFrame(frame);
  }
}