示例#1
0
qint64 QAlsaAudioInput::read(char* data, qint64 len)
{
    // Read in some audio data and write it to QIODevice, pull mode
    if ( !handle )
        return 0;

    int bytesRead = 0;
    int bytesInRingbufferBeforeRead = ringBuffer.bytesOfDataInBuffer();

    if (ringBuffer.bytesOfDataInBuffer() < len) {

        // bytesAvaiable is saved as a side effect of checkBytesReady().
        int bytesToRead = checkBytesReady();

        if (bytesToRead < 0) {
            // bytesAvailable as negative is error code, try to recover from it.
            xrun_recovery(bytesToRead);
            bytesToRead = checkBytesReady();
            if (bytesToRead < 0) {
                // recovery failed must stop and set error.
                close();
                errorState = QAudio::IOError;
                deviceState = QAudio::StoppedState;
                emit stateChanged(deviceState);
                return 0;
            }
        }

        bytesToRead = qMin<qint64>(len, bytesToRead);
        bytesToRead = qMin<qint64>(ringBuffer.freeBytes(), bytesToRead);
        bytesToRead -= bytesToRead % period_size;

        int count=0;
        int err = 0;
        while(count < 5 && bytesToRead > 0) {
            char buffer[bytesToRead];
            int chunks = bytesToRead / period_size;
            int frames = chunks * period_frames;
            if (frames > (int)buffer_frames)
                frames = buffer_frames;

            int readFrames = snd_pcm_readi(handle, buffer, frames);
            bytesRead = snd_pcm_frames_to_bytes(handle, readFrames);
            if (m_volume < 1.0f)
                QAudioHelperInternal::qMultiplySamples(m_volume, settings, buffer, buffer, bytesRead);

            if (readFrames >= 0) {
                ringBuffer.write(buffer, bytesRead);
#ifdef DEBUG_AUDIO
                qDebug() << QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(bytesRead).arg(readFrames).toLatin1().constData();
#endif
                break;
            } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
                errorState = QAudio::IOError;
                err = 0;
                break;
            } else {
                if(readFrames == -EPIPE) {
                    errorState = QAudio::UnderrunError;
                    err = snd_pcm_prepare(handle);
                } else if(readFrames == -ESTRPIPE) {
                    err = snd_pcm_prepare(handle);
                }
                if(err != 0) break;
            }
            count++;
        }

    }

    bytesRead += bytesInRingbufferBeforeRead;

    if (bytesRead > 0) {
        // got some send it onward
#ifdef DEBUG_AUDIO
        qDebug() << "frames to write to QIODevice = " <<
            snd_pcm_bytes_to_frames( handle, (int)bytesRead ) << " (" << bytesRead << ") bytes";
#endif
        if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
            return 0;

        if (pullMode) {
            qint64 l = 0;
            qint64 bytesWritten = 0;
            while (ringBuffer.bytesOfDataInBuffer() > 0) {
                l = audioSource->write(ringBuffer.availableData(), ringBuffer.availableDataBlockSize());
                if (l > 0) {
                    ringBuffer.readBytes(l);
                    bytesWritten += l;
                } else {
                    break;
                }
            }

            if (l < 0) {
                close();
                errorState = QAudio::IOError;
                deviceState = QAudio::StoppedState;
                emit stateChanged(deviceState);
            } else if (l == 0 && bytesWritten == 0) {
                if (deviceState != QAudio::IdleState) {
                    errorState = QAudio::NoError;
                    deviceState = QAudio::IdleState;
                    emit stateChanged(deviceState);
                }
            } else {
                bytesAvailable -= bytesWritten;
                totalTimeValue += bytesWritten;
                resuming = false;
                if (deviceState != QAudio::ActiveState) {
                    errorState = QAudio::NoError;
                    deviceState = QAudio::ActiveState;
                    emit stateChanged(deviceState);
                }
            }

            return bytesWritten;
        } else {
            while (ringBuffer.bytesOfDataInBuffer() > 0) {
                int size = ringBuffer.availableDataBlockSize();
                memcpy(data, ringBuffer.availableData(), size);
                data += size;
                ringBuffer.readBytes(size);
            }

            bytesAvailable -= bytesRead;
            totalTimeValue += bytesRead;
            resuming = false;
            if (deviceState != QAudio::ActiveState) {
                errorState = QAudio::NoError;
                deviceState = QAudio::ActiveState;
                emit stateChanged(deviceState);
            }

            return bytesRead;
        }
    }

    return 0;
}
示例#2
0
文件: alsa.c 项目: dusxmt/nxbelld
bool
play_pcm_buffer (playable_pcm_buffer_t *buffer)
{
  int                 status;
  snd_pcm_t          *handle;
  snd_pcm_format_t    format;
  snd_pcm_sframes_t   frames_wrote;
  int                 frames_count;
  size_t              bytes_handled;
  size_t              bytes_to_write;


  format = determine_pcm_format (&(buffer->info));
  if (format == SND_PCM_FORMAT_UNKNOWN)
    {
      fprintf (stderr, "%s: Unable to determine the beep's PCM data format.\n",
               progname);

      return false;
    }

  status = snd_pcm_open (&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
  if (status < 0)
    {
      fprintf (stderr, "%s: Failed to open the playback device: %s\n",
               progname, snd_strerror (status));

      return false;
    }

  status = snd_pcm_set_params (handle, format, SND_PCM_ACCESS_RW_INTERLEAVED,
                               buffer->info.channels, buffer->info.sample_rate,
                               1,          /* soft_resample */
                               0);         /* latency (us).*/
  if (status < 0)
    {
      fprintf (stderr, "%s: Failed to configure the playback device: %s.\n",
               progname, snd_strerror (status));

      snd_pcm_close (handle);
      return false;
    }

  bytes_handled = 0;
  while (bytes_handled < buffer->data_len)
    {
      if (buffer->data_len - bytes_handled < BUFSIZ)
        bytes_to_write = buffer->data_len - bytes_handled;
      else
        bytes_to_write = BUFSIZ;

      frames_count = snd_pcm_bytes_to_frames (handle, bytes_to_write);
      frames_wrote = snd_pcm_writei (handle, buffer->data + bytes_handled,
                                     frames_count);
      if (frames_wrote < 0)
        frames_wrote = snd_pcm_recover (handle, frames_wrote, 0);

      if (frames_wrote < 0)
        {
          fprintf (stderr, "%s: Writing to the playback device failed: %s.\n",
                   progname, snd_strerror (frames_wrote));

          snd_pcm_close (handle);
          return false;
        }

      if (frames_wrote > 0 && frames_wrote < frames_count)
        {
          fprintf (stderr, "%s: Warning: Wrote only %ld frames instead of the "
                   "expected %d to the playback device.\n",
                   progname, frames_wrote, frames_count);
        }

      bytes_handled += bytes_to_write;
    }

  snd_pcm_drain (handle);
  snd_pcm_close (handle);

  return true;
}
示例#3
0
ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes)
{
    AutoMutex lock(mLock);

    if (!mPowerLock) {
        acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioOutLock");
        mPowerLock = true;
        usleep(35000);  //201104011 [email protected], fix sound tick noise from global B

    }

    /* check if handle is still valid, otherwise we are coming out of standby */
    if(mHandle->handle == NULL) {
         nsecs_t previously = systemTime();
         mHandle->module->open(mHandle, mHandle->curDev, mHandle->curMode, mHandle->curChannels);
         nsecs_t delta = systemTime() - previously;
         LOGE("RE-OPEN AFTER STANDBY:: took %llu msecs\n", ns2ms(delta));
    }

    acoustic_device_t *aDev = acoustics();

    // For output, we will pass the data on to the acoustics module, but the actual
    // data is expected to be sent to the audio device directly as well.
    if (aDev && aDev->write)
        aDev->write(aDev, buffer, bytes);

    snd_pcm_sframes_t n;
    size_t            sent = 0;
    status_t          err;

    while (mHandle->handle && sent < bytes) {
        n = snd_pcm_writei(mHandle->handle,
                           (char *)buffer + sent,
                           snd_pcm_bytes_to_frames(mHandle->handle, bytes - sent));
        if (n == -EBADFD) {
            // Somehow the stream is in a bad state. The driver probably
            // has a bug and snd_pcm_recover() doesn't seem to handle this.
            mHandle->module->open(mHandle, mHandle->curDev, mHandle->curMode, mHandle->curChannels);

            if (aDev && aDev->recover) aDev->recover(aDev, n);
        }
        else if (n < 0) {
            if (mHandle->handle) {
                // snd_pcm_recover() will return 0 if successful in recovering from
                // an error, or -errno if the error was unrecoverable.
                n = snd_pcm_recover(mHandle->handle, n, 1);

                if (aDev && aDev->recover) aDev->recover(aDev, n);

                if (n) return static_cast<ssize_t>(n);
            }
        }
        else {
            if (mHandle->handle) {
                mFrameCount += n;
                sent += static_cast<ssize_t>(snd_pcm_frames_to_bytes(mHandle->handle, n));
            }
        }

    } 

    return sent;
}
示例#4
0
/**************************************************************************
 * 				widRecorder			[internal]
 */
static	DWORD	CALLBACK	widRecorder(LPVOID pmt)
{
    WORD		uDevID = (DWORD_PTR)pmt;
    WINE_WAVEDEV*	wwi = &WInDev[uDevID];
    WAVEHDR*		lpWaveHdr;
    DWORD		dwSleepTime;
    DWORD		bytesRead;
    enum win_wm_message msg;
    DWORD_PTR		param;
    HANDLE		ev;
    DWORD               frames_per_period;

    wwi->state = WINE_WS_STOPPED;
    InterlockedExchange((LONG*)&wwi->dwTotalRecorded, 0);
    wwi->lpQueuePtr = NULL;

    SetEvent(wwi->hStartUpEvent);

    /* make sleep time to be # of ms to output a period */
    dwSleepTime = (wwi->dwPeriodSize * 1000) / wwi->format.Format.nAvgBytesPerSec;
    frames_per_period = snd_pcm_bytes_to_frames(wwi->pcm, wwi->dwPeriodSize);
    TRACE("sleeptime=%d ms, total buffer length=%d ms (%d bytes)\n", dwSleepTime, wwi->dwBufferSize * 1000 / wwi->format.Format.nAvgBytesPerSec, wwi->dwBufferSize);

    for (;;) {
	/* wait for dwSleepTime or an event in thread's queue */
	if (wwi->lpQueuePtr != NULL && wwi->state == WINE_WS_PLAYING)
        {
            DWORD frames;
            DWORD bytes;
            DWORD read;

            lpWaveHdr = wwi->lpQueuePtr;
            /* read all the fragments accumulated so far */
            frames = snd_pcm_avail_update(wwi->pcm);
            bytes = snd_pcm_frames_to_bytes(wwi->pcm, frames);

            TRACE("frames = %d  bytes = %d state=%d\n", frames, bytes, snd_pcm_state(wwi->pcm));
            if (snd_pcm_state(wwi->pcm) == SND_PCM_STATE_XRUN)
            {
                FIXME("Recovering from XRUN!\n");
                snd_pcm_prepare(wwi->pcm);
                frames = snd_pcm_avail_update(wwi->pcm);
                bytes = snd_pcm_frames_to_bytes(wwi->pcm, frames);
                snd_pcm_start(wwi->pcm);
                snd_pcm_forward(wwi->pcm, frames - snd_pcm_bytes_to_frames(wwi->pcm, wwi->dwPeriodSize));
                continue;
            }
            while (frames > 0 && wwi->lpQueuePtr)
            {
                TRACE("bytes = %d\n", bytes);
                if (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded < bytes)
                {
                    bytes = lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded;
                    frames = snd_pcm_bytes_to_frames(wwi->pcm, bytes);
                }
                /* directly read fragment in wavehdr */
                read = wwi->read(wwi->pcm, lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, frames);
                bytesRead = snd_pcm_frames_to_bytes(wwi->pcm, read);

                TRACE("bytesRead=(%d(%d)/(%d)) -> (%d/%d)\n", bytesRead, read, frames, lpWaveHdr->dwBufferLength, lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded);
                if (read != (DWORD) -1)
                {
                    /* update number of bytes recorded in current buffer and by this device */
                    lpWaveHdr->dwBytesRecorded += bytesRead;
                    InterlockedExchangeAdd((LONG*)&wwi->dwTotalRecorded, bytesRead);
                    frames -= read;
                    bytes -= bytesRead;

                    /* buffer is full. notify client */
                    if (!snd_pcm_bytes_to_frames(wwi->pcm, lpWaveHdr->dwBytesRecorded - lpWaveHdr->dwBufferLength))
                    {
                        /* must copy the value of next waveHdr, because we have no idea of what
                         * will be done with the content of lpWaveHdr in callback
                         */
                        LPWAVEHDR	lpNext = lpWaveHdr->lpNext;

                        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
                        lpWaveHdr->dwFlags |=  WHDR_DONE;

                        wwi->lpQueuePtr = lpNext;
                        widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
                        lpWaveHdr = lpNext;
                    }
                } else {
                    WARN("read(%s, %p, %d) failed (%d/%s)\n", wwi->pcmname,
                        lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded,
                        frames, frames, snd_strerror(read));
                }
            }
        }

        ALSA_WaitRingMessage(&wwi->msgRing, dwSleepTime);

	while (ALSA_RetrieveRingMessage(&wwi->msgRing, &msg, &param, &ev))
	{
            TRACE("msg=%s param=0x%lx\n", ALSA_getCmdString(msg), param);
	    switch (msg) {
	    case WINE_WM_PAUSING:
		wwi->state = WINE_WS_PAUSED;
                /*FIXME("Device should stop recording\n");*/
		SetEvent(ev);
		break;
	    case WINE_WM_STARTING:
		wwi->state = WINE_WS_PLAYING;
		snd_pcm_start(wwi->pcm);
		SetEvent(ev);
		break;
	    case WINE_WM_HEADER:
		lpWaveHdr = (LPWAVEHDR)param;
		lpWaveHdr->lpNext = 0;

		/* insert buffer at the end of queue */
		{
		    LPWAVEHDR*	wh;
		    for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
		    *wh = lpWaveHdr;
		}
		break;
	    case WINE_WM_STOPPING:
		if (wwi->state != WINE_WS_STOPPED)
		{
		    snd_pcm_drain(wwi->pcm);

		    /* read any headers in queue */
		    widRecorder_ReadHeaders(wwi);

		    /* return current buffer to app */
		    lpWaveHdr = wwi->lpQueuePtr;
		    if (lpWaveHdr)
		    {
		        LPWAVEHDR	lpNext = lpWaveHdr->lpNext;
		        TRACE("stop %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
		        lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
		        lpWaveHdr->dwFlags |= WHDR_DONE;
		        wwi->lpQueuePtr = lpNext;
		        widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
		    }
		}
		wwi->state = WINE_WS_STOPPED;
		SetEvent(ev);
		break;
	    case WINE_WM_RESETTING:
		if (wwi->state != WINE_WS_STOPPED)
		{
		    snd_pcm_drain(wwi->pcm);
		}
		wwi->state = WINE_WS_STOPPED;
		wwi->dwTotalRecorded = 0;

		/* read any headers in queue */
		widRecorder_ReadHeaders(wwi);

		/* return all buffers to the app */
		while (wwi->lpQueuePtr) {
		    lpWaveHdr = wwi->lpQueuePtr;
		    TRACE("reset %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
                    wwi->lpQueuePtr = lpWaveHdr->lpNext;
		    lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
		    lpWaveHdr->dwFlags |= WHDR_DONE;
		    widNotifyClient(wwi, WIM_DATA, (DWORD_PTR)lpWaveHdr, 0);
		}

		SetEvent(ev);
		break;
	    case WINE_WM_CLOSING:
		wwi->hThread = 0;
		wwi->state = WINE_WS_CLOSED;
		SetEvent(ev);
		ExitThread(0);
		/* shouldn't go here */
	    default:
		FIXME("unknown message %d\n", msg);
		break;
	    }
	}
    }
    ExitThread(0);
    /* just for not generating compilation warnings... should never be executed */
    return 0;
}
示例#5
0
文件: alsa.c 项目: dusxmt/nxbelld
bool
play_pcm_file (playable_pcm_file_t *file)
{
  int                 status;
  snd_pcm_t          *handle;
  snd_pcm_format_t    format;
  snd_pcm_sframes_t   frames_wrote;
  uint8_t             playback_buf[BUFSIZ];
  int                 frames_count;
  size_t              read_bytes;


  format = determine_pcm_format (&(file->info));
  if (format == SND_PCM_FORMAT_UNKNOWN)
    {
      fprintf (stderr, "%s: Unable to determine the beep's PCM data format.\n",
               progname);

      return false;
    }

  if (fsetpos (file->stream, &(file->pcm_start_pos)) != 0)
    {
      fprintf (stderr, "%s: Failed to seek to the PCM data of `%s': %s.\n",
               progname, file->name, strerror (errno));

      return false;
    }

  status = snd_pcm_open (&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
  if (status < 0)
    {
      fprintf (stderr, "%s: Failed to open the playback device: %s\n",
               progname, snd_strerror (status));

      return false;
    }

  status = snd_pcm_set_params (handle, format, SND_PCM_ACCESS_RW_INTERLEAVED,
                               file->info.channels, file->info.sample_rate,
                               1,          /* soft_resample */
                               0);         /* latency (us).*/
  if (status < 0)
    {
      fprintf (stderr, "%s: Failed to configure the playback device: %s.\n",
               progname, snd_strerror (status));

      snd_pcm_close (handle);
      return false;
    }

  while (true)
    {
      read_bytes = fread (playback_buf, 1, BUFSIZ, file->stream);
      if (read_bytes == 0)
        {
          if (ferror (file->stream))
            {
              fprintf (stderr, "%s: An error occured while reading from `%s': %s.\n",
                       progname, file->name, strerror (errno));

              snd_pcm_close (handle);
              return false;
            }

          break;
        }
      frames_count = snd_pcm_bytes_to_frames (handle, read_bytes);
      frames_wrote = snd_pcm_writei (handle, playback_buf, frames_count);
      if (frames_wrote < 0)
        frames_wrote = snd_pcm_recover (handle, frames_wrote, 0);

      if (frames_wrote < 0)
        {
          fprintf (stderr, "%s: Writing to the playback device failed: %s.\n",
                   progname, snd_strerror (frames_wrote));

          snd_pcm_close (handle);
          return false;
        }

      if (frames_wrote > 0 && frames_wrote < frames_count)
        {
          fprintf (stderr, "%s: Warning: Wrote only %ld frames instead of the "
                   "expected %d to the playback device.\n",
                   progname, frames_wrote, frames_count);
        }
    }

  snd_pcm_drain (handle);
  snd_pcm_close (handle);

  return true;
}
示例#6
0
文件: alsa.c 项目: LighFusion/surreal
static ALCenum alsa_capture_samples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples)
{
    alsa_data *data = (alsa_data*)Device->ExtraData;

    if(data->ring)
    {
        ReadRingBuffer(data->ring, Buffer, Samples);
        return ALC_NO_ERROR;
    }

    data->last_avail -= Samples;
    while(Device->Connected && Samples > 0)
    {
        snd_pcm_sframes_t amt = 0;

        if(data->size > 0)
        {
            /* First get any data stored from the last stop */
            amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
            if((snd_pcm_uframes_t)amt > Samples) amt = Samples;

            amt = snd_pcm_frames_to_bytes(data->pcmHandle, amt);
            memmove(Buffer, data->buffer, amt);

            if(data->size > amt)
            {
                memmove(data->buffer, data->buffer+amt, data->size - amt);
                data->size -= amt;
            }
            else
            {
                free(data->buffer);
                data->buffer = NULL;
                data->size = 0;
            }
            amt = snd_pcm_bytes_to_frames(data->pcmHandle, amt);
        }
        else if(data->doCapture)
            amt = snd_pcm_readi(data->pcmHandle, Buffer, Samples);
        if(amt < 0)
        {
            ERR("read error: %s\n", snd_strerror(amt));

            if(amt == -EAGAIN)
                continue;
            if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
            {
                amt = snd_pcm_start(data->pcmHandle);
                if(amt >= 0)
                    amt = snd_pcm_avail_update(data->pcmHandle);
            }
            if(amt < 0)
            {
                ERR("restore error: %s\n", snd_strerror(amt));
                aluHandleDisconnect(Device);
                break;
            }
            /* If the amount available is less than what's asked, we lost it
             * during recovery. So just give silence instead. */
            if((snd_pcm_uframes_t)amt < Samples)
                break;
            continue;
        }

        Buffer = (ALbyte*)Buffer + amt;
        Samples -= amt;
    }
    if(Samples > 0)
        memset(Buffer, ((Device->FmtType == DevFmtUByte) ? 0x80 : 0),
               snd_pcm_frames_to_bytes(data->pcmHandle, Samples));

    return ALC_NO_ERROR;
}
示例#7
0
文件: alsa.c 项目: LighFusion/surreal
static ALCuint alsa_available_samples(ALCdevice *Device)
{
    alsa_data *data = (alsa_data*)Device->ExtraData;
    snd_pcm_sframes_t avail = 0;

    if(Device->Connected && data->doCapture)
        avail = snd_pcm_avail_update(data->pcmHandle);
    if(avail < 0)
    {
        ERR("avail update failed: %s\n", snd_strerror(avail));

        if((avail=snd_pcm_recover(data->pcmHandle, avail, 1)) >= 0)
        {
            if(data->doCapture)
                avail = snd_pcm_start(data->pcmHandle);
            if(avail >= 0)
                avail = snd_pcm_avail_update(data->pcmHandle);
        }
        if(avail < 0)
        {
            ERR("restore error: %s\n", snd_strerror(avail));
            aluHandleDisconnect(Device);
        }
    }

    if(!data->ring)
    {
        if(avail < 0) avail = 0;
        avail += snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
        if(avail > data->last_avail) data->last_avail = avail;
        return data->last_avail;
    }

    while(avail > 0)
    {
        snd_pcm_sframes_t amt;

        amt = snd_pcm_bytes_to_frames(data->pcmHandle, data->size);
        if(avail < amt) amt = avail;

        amt = snd_pcm_readi(data->pcmHandle, data->buffer, amt);
        if(amt < 0)
        {
            ERR("read error: %s\n", snd_strerror(amt));

            if(amt == -EAGAIN)
                continue;
            if((amt=snd_pcm_recover(data->pcmHandle, amt, 1)) >= 0)
            {
                if(data->doCapture)
                    amt = snd_pcm_start(data->pcmHandle);
                if(amt >= 0)
                    amt = snd_pcm_avail_update(data->pcmHandle);
            }
            if(amt < 0)
            {
                ERR("restore error: %s\n", snd_strerror(amt));
                aluHandleDisconnect(Device);
                break;
            }
            avail = amt;
            continue;
        }

        WriteRingBuffer(data->ring, data->buffer, amt);
        avail -= amt;
    }

    return RingBufferSize(data->ring);
}
示例#8
0
qint64 QAudioInputPrivate::read(char* data, qint64 len)
{
    // Read in some audio data and write it to QIODevice, pull mode
    if ( !handle )
        return 0;

    // bytesAvaiable is saved as a side effect of checkBytesReady().
    int bytesToRead = checkBytesReady();

    if (bytesToRead < 0) {
        // bytesAvailable as negative is error code, try to recover from it.
        xrun_recovery(bytesToRead);
        bytesToRead = checkBytesReady();
        if (bytesToRead < 0) {
            // recovery failed must stop and set error.
            close();
            errorState = QAudio::IOError;
            deviceState = QAudio::StoppedState;
            emit stateChanged(deviceState);
            return 0;
        }
    }

    bytesToRead = qMin<qint64>(len, bytesToRead);
    bytesToRead -= bytesToRead % period_size;
    int count=0, err = 0;
    while(count < 5) {
        int chunks = bytesToRead/period_size;
        int frames = chunks*period_frames;
        if(frames > (int)buffer_frames)
            frames = buffer_frames;
        int readFrames = snd_pcm_readi(handle, audioBuffer, frames);
        if (readFrames >= 0) {
            err = snd_pcm_frames_to_bytes(handle, readFrames);
#ifdef DEBUG_AUDIO
            qDebug()<<QString::fromLatin1("read in bytes = %1 (frames=%2)").arg(err).arg(readFrames).toLatin1().constData();
#endif
            break;
        } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
            errorState = QAudio::IOError;
            err = 0;
            break;
        } else {
            if(readFrames == -EPIPE) {
                errorState = QAudio::UnderrunError;
                err = snd_pcm_prepare(handle);
            } else if(readFrames == -ESTRPIPE) {
                err = snd_pcm_prepare(handle);
            }
            if(err != 0) break;
        }
        count++;
    }
    if(err > 0) {
        // got some send it onward
#ifdef DEBUG_AUDIO
        qDebug()<<"frames to write to QIODevice = "<<
            snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes";
#endif
        if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
            return 0;
        if (pullMode) {
            qint64 l = audioSource->write(audioBuffer,err);
            if(l < 0) {
                close();
                errorState = QAudio::IOError;
                deviceState = QAudio::StoppedState;
                emit stateChanged(deviceState);
            } else if(l == 0) {
                if (deviceState != QAudio::IdleState) {
                    errorState = QAudio::NoError;
                    deviceState = QAudio::IdleState;
                    emit stateChanged(deviceState);
                }
            } else {
                bytesAvailable -= err;
                totalTimeValue += err;
                resuming = false;
                if (deviceState != QAudio::ActiveState) {
                    errorState = QAudio::NoError;
                    deviceState = QAudio::ActiveState;
                    emit stateChanged(deviceState);
                }
            }
            return l;

        } else {
            memcpy(data,audioBuffer,err);
            bytesAvailable -= err;
            totalTimeValue += err;
            resuming = false;
            if (deviceState != QAudio::ActiveState) {
                errorState = QAudio::NoError;
                deviceState = QAudio::ActiveState;
                emit stateChanged(deviceState);
            }
            return err;
        }
    }
    return 0;
}
示例#9
0
文件: dsoutput.c 项目: r6144/wine
static HRESULT WINAPI IDsDriverBufferImpl_Unlock(PIDSDRIVERBUFFER iface,
						 LPVOID pvAudio1,DWORD dwLen1,
						 LPVOID pvAudio2,DWORD dwLen2)
{
    IDsDriverBufferImpl *This = (IDsDriverBufferImpl *)iface;
    snd_pcm_uframes_t writepos;

    if (!dwLen1)
        return DS_OK;

    /* **** */
    EnterCriticalSection(&This->pcm_crst);

    writepos = snd_pcm_bytes_to_frames(This->pcm, (DWORD_PTR)pvAudio1 - (DWORD_PTR)This->mmap_buffer);
    if (writepos == This->mmap_pos)
    {
        const snd_pcm_channel_area_t *areas;
        snd_pcm_uframes_t writelen = snd_pcm_bytes_to_frames(This->pcm, dwLen1);
        TRACE("Committing data\n");
        if (This->mmap)
            This->mmap_pos += snd_pcm_mmap_commit(This->pcm, This->mmap_pos, writelen);
        else
        {
            int ret;
            ret = snd_pcm_writei(This->pcm, pvAudio1, writelen);
            if (ret == -EPIPE)
            {
                WARN("Underrun occurred\n");
                wine_snd_pcm_recover(This->pcm, -EPIPE, 1);
                ret = snd_pcm_writei(This->pcm, pvAudio1, writelen);

                /* Advance mmap pointer a little to make dsound notice the underrun and respond to it */
                if (ret < writelen) WARN("Short write %ld/%d\n", writelen, ret);
                This->mmap_pos += This->mmap_commitahead + ret;
                This->mmap_pos %= This->mmap_buflen_frames;
            }
            else if (ret > 0)
                This->mmap_pos += ret;
            if (ret < 0)
                WARN("Committing data: %d / %s (%p %ld)\n", ret, snd_strerror(ret), pvAudio1, writelen);
        }

        if (This->mmap_pos == This->mmap_buflen_frames)
            This->mmap_pos = 0;
        if (dwLen2)
        {
            writelen = snd_pcm_bytes_to_frames(This->pcm, dwLen2);
            if (This->mmap)
            {
                snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &writelen);
                This->mmap_pos += snd_pcm_mmap_commit(This->pcm, This->mmap_pos, writelen);
            }
            else
            {
                int ret;
                ret = snd_pcm_writei(This->pcm, pvAudio2, writelen);
                if (ret < writelen) WARN("Short write %ld/%d\n", writelen, ret);
                This->mmap_pos = ret > 0 ? ret : 0;
            }
            assert(This->mmap_pos < This->mmap_buflen_frames);
        }
    }
    LeaveCriticalSection(&This->pcm_crst);
    /* **** */

    return DS_OK;
}
示例#10
0
文件: alsa.c 项目: DonelBueno/iOS
static ssize_t alsa_write(void *data, const void *buf_, size_t size_)
{
   alsa_t *alsa = (alsa_t*)data;
   const uint8_t *buf = (const uint8_t*)buf_;

   bool eagain_retry         = true;
   snd_pcm_sframes_t written = 0;
   snd_pcm_sframes_t size    = snd_pcm_bytes_to_frames(alsa->pcm, size_);

   while (size)
   {
      if (!alsa->nonblock)
      {
         int rc = snd_pcm_wait(alsa->pcm, -1);
         if (rc == -EPIPE || rc == -ESTRPIPE || rc == -EINTR)
         {
            if (snd_pcm_recover(alsa->pcm, rc, 1) < 0)
            {
               RARCH_ERR("[ALSA]: (#1) Failed to recover from error (%s)\n",
                     snd_strerror(rc));
               return -1;
            }
            continue;
         }
      }

      snd_pcm_sframes_t frames = snd_pcm_writei(alsa->pcm, buf, size);

      if (frames == -EPIPE || frames == -EINTR || frames == -ESTRPIPE)
      {
         if (snd_pcm_recover(alsa->pcm, frames, 1) < 0)
         {
            RARCH_ERR("[ALSA]: (#2) Failed to recover from error (%s)\n",
                  snd_strerror(frames));
            return -1;
         }

         break;
      }
      else if (frames == -EAGAIN && !alsa->nonblock) // Definitely not supposed to happen.
      {
         RARCH_WARN("[ALSA]: poll() was signaled, but EAGAIN returned from write.\n"
               "Your ALSA driver might be subtly broken.\n");

         if (eagain_retry)
         {
            eagain_retry = false;
            continue;
         }
         else
            return written;
      }
      else if (frames == -EAGAIN) // Expected if we're running nonblock.
      {
         return written;
      }
      else if (frames < 0)
      {
         RARCH_ERR("[ALSA]: Unknown error occured (%s).\n", snd_strerror(frames));
         return -1;
      }

      written += frames;
      buf     += (frames << 1) * (alsa->has_float ? sizeof(float) : sizeof(int16_t));
      size    -= frames;
   }

   return written;
}
ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes)
{
    AutoMutex lock(mLock);

    if (!mPowerLock) {
        acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioInLock");
        mPowerLock = true;
    }

    acoustic_device_t *aDev = acoustics();

    // If there is an acoustics module read method, then it overrides this
    // implementation (unlike AudioStreamOutALSA write).
    if (aDev && aDev->read)
        return aDev->read(aDev, buffer, bytes);

    snd_pcm_sframes_t n, frames = snd_pcm_bytes_to_frames(mHandle->handle, bytes);
    status_t          err;

    do {
        n = snd_pcm_readi(mHandle->handle, buffer, frames);
#ifdef DROPFRAME
#ifdef DROPFRAME2
        FrameNumber++;
        if (!(FrameNumber % 17) && (FrameNumber <= 1700))
        {
            n = snd_pcm_readi(mHandle->handle, buffer, frames);
        }
        if (!(FrameNumber % 176))
        {
            n = snd_pcm_readi(mHandle->handle, buffer, frames);
        }
        if (FrameNumber == 1764)
        {
            FrameNumber = 0;
            n = snd_pcm_readi(mHandle->handle, buffer, frames);
        }
#else
        FrameNumber++;
        if (FrameNumber == 624/*137* rane@2012 07 20*/)
        {
            FrameNumber = 0;
            n = snd_pcm_readi(mHandle->handle, buffer, frames);
        }
#endif
#endif
        if (n < frames) {
            if (mHandle->handle) {
                if (n < 0) {
                    n = snd_pcm_recover(mHandle->handle, n, 0);

                    if (aDev && aDev->recover) aDev->recover(aDev, n);
                } else
                    n = snd_pcm_prepare(mHandle->handle);
            }
            return static_cast<ssize_t>(n);
        }
    } while (n == -EAGAIN);

    return static_cast<ssize_t>(snd_pcm_frames_to_bytes(mHandle->handle, n));
}
示例#12
0
int alsa_play_play(alsa_play_t alsa_play, glc_audio_data_header_t *audio_hdr, char *data)
{
	snd_pcm_uframes_t frames, rem;
	snd_pcm_sframes_t ret = 0;
	unsigned int c;

	if (audio_hdr->id != alsa_play->id)
		return 0;

	if (!alsa_play->pcm) {
		glc_log(alsa_play->glc, GLC_ERROR, "alsa_play", "broken stream %d",
			 alsa_play->id);
		return EINVAL;
	}

	frames = snd_pcm_bytes_to_frames(alsa_play->pcm, audio_hdr->size);
	glc_utime_t time = glc_state_time(alsa_play->glc);
	glc_utime_t duration = ((glc_utime_t) 1000000000 * (glc_utime_t) frames) /
			       (glc_utime_t) alsa_play->rate;

	if (time + alsa_play->silence_threshold + duration < audio_hdr->time) {
		struct timespec ts = {
		.tv_sec = (audio_hdr->time - time - duration - alsa_play->silence_threshold)/1000000000,
		.tv_nsec = (audio_hdr->time - time - duration - alsa_play->silence_threshold)%1000000000 };
		nanosleep(&ts,NULL);
	}
	/*
	 * This condition determine what will be the initial audio packet.
	 * it is preferable to be ahead by < duration/2 than behind
	 * the video by > duration/2
	 */
	else if (time > audio_hdr->time + duration/2) {
		glc_log(alsa_play->glc, GLC_DEBUG, "alsa_play",
			"dropped packet. now %" PRId64 " ts %" PRId64,
			time, audio_hdr->time);
		return 0;
	}

	rem = frames;

	while (rem > 0) {
		/* alsa is horrible... */
		/*snd_pcm_wait(alsa_play->pcm, duration);*/

		if (alsa_play->flags & GLC_AUDIO_INTERLEAVED)
			ret = snd_pcm_writei(alsa_play->pcm,
					    &data[snd_pcm_frames_to_bytes(alsa_play->pcm, frames - rem)],
					    rem);
		else {
			for (c = 0; c < alsa_play->channels; c++)
				alsa_play->bufs[c] =
					&data[snd_pcm_samples_to_bytes(alsa_play->pcm, frames)
					      * c + snd_pcm_samples_to_bytes(alsa_play->pcm, frames - rem)];
			ret = snd_pcm_writen(alsa_play->pcm, alsa_play->bufs, rem);
		}

		if (ret == 0)
			break;

		if ((ret == -EBUSY) || (ret == -EAGAIN))
			break;
		else if (ret < 0) {
			if ((ret = alsa_play_xrun(alsa_play, ret))) {
				glc_log(alsa_play->glc, GLC_ERROR, "alsa_play",
					 "xrun recovery failed: %s", snd_strerror(-ret));
				return ret;
			}
		} else
			rem -= ret;
	}

	return 0;
}
ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes)
{
    android::AutoMutex lock(mLock);

    if (!mPowerLock) {
        acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioOutLock");
        mPowerLock = true;
    }

    acoustic_device_t *aDev = acoustics();

    // For output, we will pass the data on to the acoustics module, but the actual
    // data is expected to be sent to the audio device directly as well.
    if (aDev && aDev->write)
        aDev->write(aDev, buffer, bytes);

    snd_pcm_sframes_t n;
    size_t            sent = 0;
    status_t          err = 0;

    do {
        if (mHandle->mmap)
            n = snd_pcm_mmap_writei(mHandle->handle,
                               (char *)buffer + sent,
                               snd_pcm_bytes_to_frames(mHandle->handle, bytes - sent));
	else
            n = snd_pcm_writei(mHandle->handle,
                               (char *)buffer + sent,
                               snd_pcm_bytes_to_frames(mHandle->handle, bytes - sent));
        if (n == -EBADFD) {
            LOGW("badstate and do recovery.....");
            switch(snd_pcm_state(mHandle->handle)){
                case SND_PCM_STATE_SETUP:
                    err = snd_pcm_prepare(mHandle->handle);
                    if(err < 0) LOGW("snd_pcm_prepare failed");
                    break;
                case SND_PCM_STATE_SUSPENDED:
                    snd_pcm_resume(mHandle->handle);
                    if(err < 0) LOGW("snd_pcm_resume failed");
                    snd_pcm_prepare(mHandle->handle);
                    if(err < 0) LOGW("snd_pcm_prepare failed");
                    break;
                default:
                    // Somehow the stream is in a bad state. The driver probably
                    // has a bug and snd_pcm_recover() doesn't seem to handle this.
                    mHandle->module->open(mHandle, mHandle->curDev, mHandle->curMode);
                    break;
            }

            if(err < 0 ) mHandle->module->open(mHandle, mHandle->curDev, mHandle->curMode);

            if (aDev && aDev->recover) aDev->recover(aDev, n);
        }
        else if (n < 0) {
            if (mHandle->handle) {
                LOGW("underrun and do recovery.....");
                // snd_pcm_recover() will return 0 if successful in recovering from
                // an error, or -errno if the error was unrecoverable.
                n = snd_pcm_recover(mHandle->handle, n, 1);

                if (aDev && aDev->recover) aDev->recover(aDev, n);

                if (n) return static_cast<ssize_t>(n);
            }
        }
        else {
            mFrameCount += n;
            sent += static_cast<ssize_t>(snd_pcm_frames_to_bytes(mHandle->handle, n));
        }

    } while (mHandle->handle && sent < bytes);

    return sent;
}
示例#14
0
bool PAPlayer::AddPacketsToStream(int stream, CAudioDecoder &dec)
{

  if (!m_pStream[stream] || dec.GetStatus() == STATUS_NO_FILE)
    return false;

    bool ret = false;

    int nAvail = snd_pcm_frames_to_bytes(m_pStream[stream], snd_pcm_avail_update(m_pStream[stream]));
    if (nAvail < PACKET_SIZE) {
        return false;
    }

    if (m_resampler[stream].GetData(m_packet[stream][0].packet))
    {
        // got some data from our resampler - construct audio packet
        m_packet[stream][0].length = PACKET_SIZE;
        m_packet[stream][0].stream = stream;

  unsigned char *pcmPtr = m_packet[stream][0].packet;

  // handle volume de-amp
  m_amp[stream].DeAmplify((short *)pcmPtr, m_packet[stream][0].length / 2);

    StreamCallback(&m_packet[stream][0]);

  while ( pcmPtr < m_packet[stream][0].packet + m_packet[stream][0].length) {
    int nPeriodSize = snd_pcm_frames_to_bytes(m_pStream[stream],m_periods[stream]);
    if ( pcmPtr + nPeriodSize >  m_packet[stream][0].packet + m_packet[stream][0].length) {
      nPeriodSize = m_packet[stream][0].packet + m_packet[stream][0].length - pcmPtr;
    }

    int framesToWrite = snd_pcm_bytes_to_frames(m_pStream[stream],nPeriodSize);
    int writeResult = snd_pcm_writei(m_pStream[stream], pcmPtr, framesToWrite);
    if (  writeResult == -EPIPE  ) {
      CLog::Log(LOGDEBUG, "PAPlayer::AddPacketsToStream - buffer underun (tried to write %d frames)",
      framesToWrite);
      int err = snd_pcm_prepare(m_pStream[stream]);
        CHECK_ALSA(LOGERROR,"prepare after EPIPE", err);
    }
    else if (writeResult != framesToWrite) {
      CLog::Log(LOGERROR, "PAPlayer::AddPacketsToStream - failed to write %d frames. "
      "bad write (err: %d) - %s",
        framesToWrite, writeResult, snd_strerror(writeResult));
      break;
    }
    //else
        //    m_bytesSentOut += nPeriodSize;

    pcmPtr += nPeriodSize;
  }

      // something done
      ret = true;
    }
    else
    { // resampler wants more data - let's feed it
      int amount = m_resampler[stream].GetInputSamples();
      if (amount > 0 && amount <= (int)dec.GetDataSize())
      {
        // needs some data - let's feed it
        m_resampler[stream].PutFloatData((float *)dec.GetData(amount), amount);
        ret = true;
      }
    }

  return ret;
}
示例#15
0
文件: dscapture.c 项目: mikekap/wine
/**
 * Allocate the memory-mapped buffer for direct sound, and set up the
 * callback.
 */
static int CreateMMAP(IDsCaptureDriverBufferImpl* pdbi)
{
    snd_pcm_t *pcm = pdbi->pcm;
    snd_pcm_format_t format;
    snd_pcm_uframes_t frames, ofs, avail, psize, boundary;
    unsigned int channels, bits_per_sample, bits_per_frame;
    int err, mmap_mode;
    const snd_pcm_channel_area_t *areas;
    snd_pcm_hw_params_t *hw_params = pdbi->hw_params;
    snd_pcm_sw_params_t *sw_params = pdbi->sw_params;

    mmap_mode = snd_pcm_type(pcm);

    if (mmap_mode == SND_PCM_TYPE_HW)
        TRACE("mmap'd buffer is a direct hardware buffer.\n");
    else if (mmap_mode == SND_PCM_TYPE_DMIX)
        TRACE("mmap'd buffer is an ALSA dmix buffer\n");
    else
        TRACE("mmap'd buffer is an ALSA type %d buffer\n", mmap_mode);

    err = snd_pcm_hw_params_get_period_size(hw_params, &psize, NULL);
    err = snd_pcm_hw_params_get_format(hw_params, &format);
    err = snd_pcm_hw_params_get_buffer_size(hw_params, &frames);
    err = snd_pcm_hw_params_get_channels(hw_params, &channels);
    bits_per_sample = snd_pcm_format_physical_width(format);
    bits_per_frame = bits_per_sample * channels;

    if (TRACE_ON(dsalsa))
        ALSA_TraceParameters(hw_params, NULL, FALSE);

    TRACE("format=%s  frames=%ld  channels=%d  bits_per_sample=%d  bits_per_frame=%d\n",
          snd_pcm_format_name(format), frames, channels, bits_per_sample, bits_per_frame);

    pdbi->mmap_buflen_frames = frames;
    snd_pcm_sw_params_current(pcm, sw_params);
    snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 0);
    snd_pcm_sw_params_get_boundary(sw_params, &boundary);
    snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, boundary);
    snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, INT_MAX);
    snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0);
    snd_pcm_sw_params_set_avail_min(pcm, sw_params, 0);
    err = snd_pcm_sw_params(pcm, sw_params);

    pdbi->mmap_ofs_bytes = 0;
    if (!pdbi->mmap)
    {
        pdbi->mmap_buffer = NULL;

        frames = snd_pcm_bytes_to_frames(pdbi->pcm, pdbi->mmap_buflen_bytes);
        snd_pcm_format_set_silence(format, pdbi->presented_buffer, frames);
        pdbi->mmap_pos = 0;
    }
    else
    {
        err = snd_pcm_mmap_begin(pcm, &areas, &ofs, &avail);
        if ( err < 0 )
        {
            ERR("Can't map sound device for direct access: %s/%d\n", snd_strerror(err), err);
            return DSERR_GENERIC;
        }
        snd_pcm_format_set_silence(format, areas->addr, pdbi->mmap_buflen_frames);
        pdbi->mmap_pos = ofs + snd_pcm_mmap_commit(pcm, ofs, 0);
        pdbi->mmap_buffer = areas->addr;
    }

    TRACE("created mmap buffer of %ld frames (%d bytes) at %p\n",
        pdbi->mmap_buflen_frames, pdbi->mmap_buflen_bytes, pdbi->mmap_buffer);

    return DS_OK;
}
示例#16
0
文件: dscapture.c 项目: mikekap/wine
/** Fill buffers, for starting and stopping
 * Alsa won't start playing until everything is filled up
 * This also updates mmap_pos
 *
 * Returns: Amount of periods in use so snd_pcm_avail_update
 * doesn't have to be called up to 4x in GetPosition()
 */
static snd_pcm_uframes_t CommitAll(IDsCaptureDriverBufferImpl *This, DWORD forced)
{
    const snd_pcm_channel_area_t *areas;
    snd_pcm_uframes_t used;
    const snd_pcm_uframes_t commitahead = This->mmap_buflen_frames;

    used = This->mmap_buflen_frames - snd_pcm_avail_update(This->pcm);
    TRACE("%p needs to commit to %lu, used: %lu\n", This, commitahead, used);
    if (used < commitahead && (forced || This->play_looping))
    {
        snd_pcm_uframes_t done, putin = commitahead - used;
        if (This->mmap)
        {
            snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
            CopyData(This, This->mmap_pos, putin);
            done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);

            This->mmap_pos += done;
            used += done;
            putin = commitahead - used;

            if (This->mmap_pos == This->mmap_buflen_frames && (snd_pcm_sframes_t)putin > 0 && This->play_looping)
            {
                This->mmap_ofs_bytes += snd_pcm_frames_to_bytes(This->pcm, This->mmap_buflen_frames);
                This->mmap_ofs_bytes %= This->mmap_buflen_bytes;

                snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
                CopyData(This, This->mmap_pos, putin);
                done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);

                This->mmap_pos += done;
                used += done;
            }
        }
        else
        {
            DWORD pos;
            snd_pcm_sframes_t ret;

            snd_pcm_uframes_t cap = snd_pcm_bytes_to_frames(This->pcm, This->mmap_buflen_bytes);
            pos = realpos_to_fakepos(This, This->mmap_pos);
            if (This->mmap_pos + putin > cap)
                putin = cap - This->mmap_pos;
            ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
            if (ret == -EPIPE)
            {
                WARN("Underrun occurred\n");
                snd_pcm_prepare(This->pcm);
                ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
                snd_pcm_start(This->pcm);
            }
            if (ret < 0)
            {
                WARN("Committing data: %ld / %s (%ld)\n", ret, snd_strerror(ret), putin);
                ret = 0;
            }
            This->mmap_pos += ret;
            used += ret;
            /* At this point mmap_pos may be >= This->mmap_pos this is harmless
             * realpos_to_fakepos handles it well, and below it is truncated
             */

            putin = commitahead - used;
            if (putin > 0)
            {
                pos = realpos_to_fakepos(This, This->mmap_pos);
                ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
                if (ret > 0)
                {
                    This->mmap_pos += ret;
                    used += ret;
                }
            }
        }

    }

    if (This->mmap_pos >= This->mmap_buflen_frames)
    {
        This->mmap_ofs_bytes += snd_pcm_frames_to_bytes(This->pcm, This->mmap_buflen_frames);
        This->mmap_ofs_bytes %= This->mmap_buflen_bytes;
        This->mmap_pos -= This->mmap_buflen_frames;
    }

    return used;
}