Exemple #1
0
void
impl::muxer::mux(volatile const bool& terminate)
{
    atf::utils::auto_array< struct pollfd > poll_fds(new struct pollfd[m_nfds]);
    for (size_t i = 0; i < m_nfds; i++) {
        poll_fds[i].fd = m_fds[i];
        poll_fds[i].events = POLLIN;
    }

    size_t nactive = m_nfds;
    while (nactive > 0 && !terminate) {
        int ret;
        while (!terminate && (ret = safe_poll(poll_fds.get(), 2, 250)) == 0) {}

        for (size_t i = 0; !terminate && i < m_nfds; i++) {
            if (poll_fds[i].events == 0)
                continue;

            if (poll_fds[i].revents & POLLHUP) {
                // Any data still available at this point will be processed by
                // a call to the flush method.
                poll_fds[i].events = 0;

                INV(nactive >= 1);
                nactive--;
            } else if (poll_fds[i].revents & (POLLIN | POLLRDNORM | POLLRDBAND |
                                       POLLPRI)) {
                (void)read_one(i, poll_fds[i].fd, m_buffers[i], true);
            }
        }
    }
}
Exemple #2
0
bool
ALSAPCMPlayer::Start(PCMDataSource &_source)
{
  const unsigned new_sample_rate = _source.GetSampleRate();

  if ((nullptr != source) &&
      alsa_handle &&
      (source->GetSampleRate() == new_sample_rate)) {
    /* just change the source / resume playback */
    bool success = false;
    DispatchWait(io_service, [this, &_source, &success]() {
      bool recovered_from_underrun = false;

      switch (snd_pcm_state(alsa_handle.get())) {
      case SND_PCM_STATE_XRUN:
        if (0 != snd_pcm_prepare(alsa_handle.get()))
          return;
        else {
          recovered_from_underrun = true;
          success = true;
        }
        break;

      case SND_PCM_STATE_RUNNING:
        success = true;
        break;

      default:
        return;
      }

      if (success) {
        source = &_source;

        if (recovered_from_underrun) {
          const size_t n = buffer_size / channels;
          const size_t n_read = FillPCMBuffer(buffer.get(), n);
          if (!WriteFrames(n_read)) {
            success = false;
            return;
          }
        }

        if (success)
          StartEventHandling();
      }
    });
    if (success)
      return true;
  }

  Stop();

  assert(!alsa_handle);

  AlsaHandleUniquePtr new_alsa_handle = MakeAlsaHandleUniquePtr();
  {
    const char *alsa_device = ALSAEnv::GetALSADeviceName();

    snd_pcm_t *raw_alsa_handle;
    int alsa_error = snd_pcm_open(&raw_alsa_handle, alsa_device,
                                  SND_PCM_STREAM_PLAYBACK, 0);
    if (alsa_error < 0) {
      LogFormat("snd_pcm_open(0x%p, \"%s\", SND_PCM_STREAM_PLAYBACK, 0) "
                    "failed: %s",
                &alsa_handle, alsa_device, snd_strerror(alsa_error));
      return false;
    }
    new_alsa_handle = MakeAlsaHandleUniquePtr(raw_alsa_handle);
    assert(new_alsa_handle);
  }

  unsigned latency = ALSAEnv::GetALSALatency();

  channels = 1;
  bool big_endian_source = _source.IsBigEndian();
  if (!SetParameters(*new_alsa_handle, new_sample_rate, big_endian_source,
                     latency, channels))
    return false;

  snd_pcm_sframes_t n_available = snd_pcm_avail(new_alsa_handle.get());
  if (n_available <= 0) {
    LogFormat("snd_pcm_avail(0x%p) failed: %ld - %s",
              new_alsa_handle.get(),
              static_cast<long>(n_available),
              snd_strerror(static_cast<int>(n_available)));
    return false;
  }

  buffer_size = static_cast<snd_pcm_uframes_t>(n_available * channels);
  buffer = std::unique_ptr<int16_t[]>(new int16_t[buffer_size]);

  /* Why does Boost.Asio make it so hard to register a set of of standard
     poll() descriptors (struct pollfd)? */
  int poll_fds_count = snd_pcm_poll_descriptors_count(new_alsa_handle.get());
  if (poll_fds_count < 1) {
    LogFormat("snd_pcm_poll_descriptors_count(0x%p) returned %d",
              new_alsa_handle.get(),
              poll_fds_count);
    return false;
  }

  std::unique_ptr<struct pollfd[]> poll_fds(
      new struct pollfd[poll_fds_count]);
  BOOST_VERIFY(
      poll_fds_count ==
          snd_pcm_poll_descriptors(new_alsa_handle.get(),
                                   poll_fds.get(),
                                   static_cast<unsigned>(poll_fds_count)));

  for (int i = 0; i < poll_fds_count; ++i) {
    if ((poll_fds[i].events & POLLIN) || (poll_fds[i].events & POLLPRI)) {
      read_poll_descs.emplace_back(
          boost::asio::posix::stream_descriptor(io_service, poll_fds[i].fd));
    }
    if (poll_fds[i].events & POLLOUT) {
      write_poll_descs.emplace_back(
          boost::asio::posix::stream_descriptor(io_service, poll_fds[i].fd));
    }
  }

  source = &_source;
  size_t n_read = FillPCMBuffer(buffer.get(), static_cast<size_t>(n_available));

  if (0 == n_read) {
    LogFormat("ALSA PCMPlayer started with data source which "
                  "does not deliver any data");
    return false;
  }

  if (!WriteFrames(*new_alsa_handle, buffer.get(),
                   static_cast<size_t>(n_available), false))
    return false;

  alsa_handle = std::move(new_alsa_handle);

  StartEventHandling();

  return true;
}