Ejemplo n.º 1
0
static gint
gst_tinyalsa_sink_write (GstAudioSink * asink, gpointer data, guint length)
{
  GstTinyalsaSink *sink = GST_TINYALSA_SINK (asink);
  int ret;

again:
  GST_DEBUG_OBJECT (sink, "Starting write");

  ret = pcm_write (sink->pcm, data, length);
  if (ret == -EPIPE) {
    GST_WARNING_OBJECT (sink, "Got an underrun");

    if (pcm_prepare (sink->pcm) < 0) {
      GST_ERROR_OBJECT (sink, "Could not prepare device: %s",
          pcm_get_error (sink->pcm));
      return -1;
    }

    goto again;

  } else if (ret < 0) {
    GST_ERROR_OBJECT (sink, "Could not write data to device: %s",
        pcm_get_error (sink->pcm));
    return -1;
  }

  GST_DEBUG_OBJECT (sink, "Wrote %u bytes", length);

  return length;
}
bool TinyAlsaCtlPortConfig::doOpenStream(StreamDirection streamDirection, std::string &error)
{
    struct pcm *&streamHandle = _streamHandle[streamDirection];
    struct pcm_config pcmConfig;

    const AlsaCtlPortConfig::PortConfig &portConfig = getPortConfig();

    // Fill PCM configuration structure
    pcmConfig.channels = portConfig.channelNumber;
    pcmConfig.rate = portConfig.sampleRate;

    // Check Format is supported by the plugin
    if (portConfig.format >= pcmFormatTranslationTableSize) {

        error = "The format n°" + asString(portConfig.format) +
                " is not supported by the TinyAlsa plugin";
        return false;
    }

    uint8_t format = pcmFormatTranslationTable[portConfig.format].formatAsNumerical;

    // Check format is supported by Tinyalsa
    if (format == std::numeric_limits<uint8_t>::max()) {

        error = "The format " + pcmFormatTranslationTable[portConfig.format].formatAsString +
                " is not supported by Tinyalsa";
        return false;
    }

    pcmConfig.format = static_cast<pcm_format>(format);

    pcmConfig.period_size       = _periodTimeMs * pcmConfig.rate / _msPerSec;
    pcmConfig.period_count      = _nbRingBuffer;
    pcmConfig.start_threshold   = 0;
    pcmConfig.stop_threshold    = 0;
    pcmConfig.silence_threshold = 0;
    pcmConfig.silence_size      = 0;
    pcmConfig.avail_min         = 0;

    // Open and configure
    streamHandle = pcm_open(getCardNumber(),
                            getDeviceNumber(),
                            streamDirection == Capture ? PCM_IN : PCM_OUT,
                            &pcmConfig);

    // Prepare the stream
    if (!pcm_is_ready(streamHandle) || (pcm_prepare(streamHandle) != 0)) {

        // Format error
        error = formatAlsaError(streamDirection, "open", pcm_get_error(streamHandle));

        doCloseStream(streamDirection);
        return false;
    }

    return true;
}
Ejemplo n.º 3
0
static void
gst_tinyalsa_sink_reset (GstAudioSink * asink)
{
  GstTinyalsaSink *sink = GST_TINYALSA_SINK (asink);

  if (pcm_stop (sink->pcm) < 0) {
    GST_ERROR_OBJECT (sink, "Could not stop device: %s",
        pcm_get_error (sink->pcm));
  }

  if (pcm_prepare (sink->pcm) < 0) {
    GST_ERROR_OBJECT (sink, "Could not prepare device: %s",
        pcm_get_error (sink->pcm));
  }
}
Ejemplo n.º 4
0
static gboolean
gst_tinyalsa_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec)
{
  GstTinyalsaSink *sink = GST_TINYALSA_SINK (asink);
  struct pcm_config config = { 0, };
  struct pcm_params *params = NULL;
  int period_size_min, period_size_max;
  int periods_min, periods_max;

  pcm_config_from_spec (&config, spec);

  GST_DEBUG_OBJECT (sink, "Requesting %u periods of %u frames",
      config.period_count, config.period_size);

  params = pcm_params_get (sink->card, sink->device, PCM_OUT);
  if (!params)
    GST_ERROR_OBJECT (sink, "Could not get PCM params");

  period_size_min = pcm_params_get_min (params, PCM_PARAM_PERIOD_SIZE);
  period_size_max = pcm_params_get_max (params, PCM_PARAM_PERIOD_SIZE);
  periods_min = pcm_params_get_min (params, PCM_PARAM_PERIODS);
  periods_max = pcm_params_get_max (params, PCM_PARAM_PERIODS);

  pcm_params_free (params);

  /* Snap period size/count to the permitted range */
  config.period_size =
      CLAMP (config.period_size, period_size_min, period_size_max);
  config.period_count = CLAMP (config.period_count, periods_min, periods_max);

  /* mutex with getcaps */
  GST_OBJECT_LOCK (sink);

  sink->pcm = pcm_open (sink->card, sink->device, PCM_OUT | PCM_NORESTART,
      &config);

  GST_OBJECT_UNLOCK (sink);

  if (!sink->pcm || !pcm_is_ready (sink->pcm)) {
    GST_ERROR_OBJECT (sink, "Could not open device: %s",
        pcm_get_error (sink->pcm));
    goto fail;
  }

  if (pcm_prepare (sink->pcm) < 0) {
    GST_ERROR_OBJECT (sink, "Could not prepare device: %s",
        pcm_get_error (sink->pcm));
    goto fail;
  }

  spec->segsize = pcm_frames_to_bytes (sink->pcm, config.period_size);
  spec->segtotal = config.period_count;

  GST_DEBUG_OBJECT (sink, "Configured for %u periods of %u frames",
      config.period_count, config.period_size);

  return TRUE;

fail:
  if (sink->pcm)
    pcm_close (sink->pcm);

  return FALSE;
}
Ejemplo n.º 5
0
static int play_file(unsigned rate, unsigned channels, int fd,
              unsigned flags, const char *device, unsigned data_sz)
{
    struct pcm *pcm;
    struct mixer *mixer;
    struct pcm_ctl *ctl = NULL;
    unsigned bufsize;
    char *data;
    long avail;
    long frames;
    int nfds = 1;
    struct snd_xferi x;
    unsigned offset = 0;
    int err;
    static int start = 0;
    struct pollfd pfd[1];
    int remainingData = 0;

    flags |= PCM_OUT;

    if (channels == 1)
        flags |= PCM_MONO;
    else if (channels == 6)
	flags |= PCM_5POINT1;
    else
        flags |= PCM_STEREO;

    if (debug)
        flags |= DEBUG_ON;
    else
        flags |= DEBUG_OFF;

    pcm = pcm_open(flags, device);
    if (pcm < 0)
        return pcm;

    if (!pcm_ready(pcm)) {
        pcm_close(pcm);
        return -EBADFD;
    }

#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
    if (compressed) {
       struct snd_compr_caps compr_cap;
       struct snd_compr_params compr_params;
       if (ioctl(pcm->fd, SNDRV_COMPRESS_GET_CAPS, &compr_cap)) {
          fprintf(stderr, "Aplay: SNDRV_COMPRESS_GET_CAPS, failed Error no %d \n", errno);
          pcm_close(pcm);
          return -errno;
       }
       if (!period)
           period = compr_cap.min_fragment_size;
           switch (get_compressed_format(compr_codec)) {
           case FORMAT_MP3:
               compr_params.codec.id = compr_cap.codecs[FORMAT_MP3];
               break;
           case FORMAT_AC3_PASS_THROUGH:
               compr_params.codec.id = compr_cap.codecs[FORMAT_AC3_PASS_THROUGH];
               printf("codec -d = %x\n", compr_params.codec.id);
               break;
           default:
               break;
           }
       if (ioctl(pcm->fd, SNDRV_COMPRESS_SET_PARAMS, &compr_params)) {
          fprintf(stderr, "Aplay: SNDRV_COMPRESS_SET_PARAMS,failed Error no %d \n", errno);
          pcm_close(pcm);
          return -errno;
       }
    }
#endif
    pcm->channels = channels;
    pcm->rate = rate;
    pcm->flags = flags;
    pcm->format = format;
    if (set_params(pcm)) {
        fprintf(stderr, "Aplay:params setting failed\n");
        pcm_close(pcm);
        return -errno;
    }

    if (!pcm_flag) {
       if (pcm_prepare(pcm)) {
          fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
          pcm_close(pcm);
          return -errno;
       }
       if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
          fprintf(stderr, "Aplay: Hostless IOCTL_START Error no %d \n", errno);
          pcm_close(pcm);
          return -errno;
       }
        while(1);
    }

    remainingData = data_sz;

    if (flags & PCM_MMAP) {
        u_int8_t *dst_addr = NULL;
        struct snd_pcm_sync_ptr *sync_ptr1 = pcm->sync_ptr;
        if (mmap_buffer(pcm)) {
             fprintf(stderr, "Aplay:params setting failed\n");
             pcm_close(pcm);
             return -errno;
        }
        if (pcm_prepare(pcm)) {
          fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
          pcm_close(pcm);
          return -errno;
        }

        bufsize = pcm->period_size;
        if (debug)
          fprintf(stderr, "Aplay:bufsize = %d\n", bufsize);

        pfd[0].fd = pcm->timer_fd;
        pfd[0].events = POLLIN;

        frames = (pcm->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4);
        for (;;) {
             if (!pcm->running) {
                  if (pcm_prepare(pcm)) {
                      fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
                      pcm_close(pcm);
                      return -errno;
                  }
                  pcm->running = 1;
                  start = 0;
             }
             /* Sync the current Application pointer from the kernel */
             pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
             err = sync_ptr(pcm);
             if (err == EPIPE) {
                 fprintf(stderr, "Aplay:Failed in sync_ptr \n");
                 /* we failed to make our window -- try to restart */
                 pcm->underruns++;
                 pcm->running = 0;
                 continue;
             }
             /*
              * Check for the available buffer in driver. If available buffer is
              * less than avail_min we need to wait
              */
             avail = pcm_avail(pcm);
             if (avail < 0) {
                 fprintf(stderr, "Aplay:Failed in pcm_avail\n");
                 pcm_close(pcm);
                 return avail;
             }
             if (avail < pcm->sw_p->avail_min) {
                 poll(pfd, nfds, TIMEOUT_INFINITE);
                 continue;
             }
             /*
              * Now that we have buffer size greater than avail_min available to
              * to be written we need to calcutate the buffer offset where we can
              * start writting.
              */
             dst_addr = dst_address(pcm);

             if (debug) {
                 fprintf(stderr, "dst_addr = 0x%08x\n", dst_addr);
                 fprintf(stderr, "Aplay:avail = %d frames = %d\n",avail, frames);
                 fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  pcm->buffer_size %d  sync_ptr->c.control.appl_ptr %ld\n",
                            pcm->sync_ptr->s.status.hw_ptr,
                            pcm->buffer_size,
                            pcm->sync_ptr->c.control.appl_ptr);
             }

             /*
              * Read from the file to the destination buffer in kernel mmaped buffer
              * This reduces a extra copy of intermediate buffer.
              */
             memset(dst_addr, 0x0, bufsize);

             if (data_sz && !piped) {
                 if (remainingData < bufsize) {
                     bufsize = remainingData;
                     frames = (pcm->flags & PCM_MONO) ? (remainingData / 2) : (remainingData / 4);
                 }
             }

             err = read(fd, dst_addr , bufsize);
             if (debug)
                 fprintf(stderr, "read %d bytes from file\n", err);
             if (err <= 0)
                 break;

             if (data_sz && !piped) {
                 remainingData -= bufsize;
                 if (remainingData <= 0)
                     break;
             }

             /*
              * Increment the application pointer with data written to kernel.
              * Update kernel with the new sync pointer.
              */
             pcm->sync_ptr->c.control.appl_ptr += frames;
             pcm->sync_ptr->flags = 0;

             err = sync_ptr(pcm);
             if (err == EPIPE) {
                 fprintf(stderr, "Aplay:Failed in sync_ptr 2 \n");
                 /* we failed to make our window -- try to restart */
                 pcm->underruns++;
                 pcm->running = 0;
                 continue;
             }

             if (debug) {
                 fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  sync_ptr->c.control.appl_ptr %ld\n",
                            pcm->sync_ptr->s.status.hw_ptr,
                            pcm->sync_ptr->c.control.appl_ptr);
#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
                 if (compressed && start) {
                    struct snd_compr_tstamp tstamp;
		    if (ioctl(pcm->fd, SNDRV_COMPRESS_TSTAMP, &tstamp))
			fprintf(stderr, "Aplay: failed SNDRV_COMPRESS_TSTAMP\n");
                    else
	                fprintf(stderr, "timestamp = %lld\n", tstamp.timestamp);
		}
#endif
             }
             /*
              * If we have reached start threshold of buffer prefill,
              * its time to start the driver.
              */
                 if(start)
                     goto start_done;
                 if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
                     err = -errno;
                     if (errno == EPIPE) {
                         fprintf(stderr, "Aplay:Failed in SNDRV_PCM_IOCTL_START\n");
                         /* we failed to make our window -- try to restart */
                         pcm->underruns++;
                         pcm->running = 0;
                         continue;
                    } else {
                        fprintf(stderr, "Aplay:Error no %d \n", errno);
                        pcm_close(pcm);
                        return -errno;
                    }
                } else
                    start = 1;

start_done:
                offset += frames;
        }
        while(1) {
            pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
            sync_ptr(pcm);
            /*
             * Check for the available buffer in driver. If available buffer is
             * less than avail_min we need to wait
             */
            if (pcm->sync_ptr->s.status.hw_ptr >= pcm->sync_ptr->c.control.appl_ptr) {
                fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  sync_ptr->c.control.appl_ptr %ld\n",
                           pcm->sync_ptr->s.status.hw_ptr,
                           pcm->sync_ptr->c.control.appl_ptr);
                break;
            } else
                poll(pfd, nfds, TIMEOUT_INFINITE);
        }
    } else {
        if (pcm_prepare(pcm)) {
            fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
            pcm_close(pcm);
            return -errno;
        }

        bufsize = pcm->period_size;

        data = calloc(1, bufsize);
        if (!data) {
            fprintf(stderr, "Aplay:could not allocate %d bytes\n", bufsize);
            pcm_close(pcm);
            return -ENOMEM;
        }

        if (data_sz && !piped) {
            if (remainingData < bufsize)
                bufsize = remainingData;
        }

        while (read(fd, data, bufsize) > 0) {
            if (pcm_write(pcm, data, bufsize)){
                fprintf(stderr, "Aplay: pcm_write failed\n");
                free(data);
                pcm_close(pcm);
                return -errno;
            }
            memset(data, 0, bufsize);

            if (data_sz && !piped) {
                remainingData -= bufsize;
                if (remainingData <= 0)
                    break;
                if (remainingData < bufsize)
                       bufsize = remainingData;
            }
        }
        free(data);
    }
    fprintf(stderr, "Aplay: Done playing\n");
    pcm_close(pcm);
    return 0;
}
Ejemplo n.º 6
0
int play_file(unsigned rate, unsigned channels, int fd, unsigned count,
              unsigned flags, const char *device)
{
    struct pcm *pcm;
    struct mixer *mixer;
    struct pcm_ctl *ctl = NULL;
    unsigned bufsize;
    char *data;
    long avail;
    long frames;
    int nfds = 1;
    struct snd_xferi x;
    unsigned offset = 0;
    int err;
    static int start = 0;
    struct pollfd pfd[1];

    flags |= PCM_OUT;

    if (channels == 1)
        flags |= PCM_MONO;
    else
        flags |= PCM_STEREO;

    if (debug)
        flags |= DEBUG_ON;
    else
        flags |= DEBUG_OFF;

    pcm = pcm_open(flags, device);
    if (pcm < 0)
        return pcm;

    if (!pcm_ready(pcm)) {
        pcm_close(pcm);
        return -EBADFD;
    }
    pcm->channels = channels;
    pcm->rate = rate;
    pcm->flags = flags;
    if (set_params(pcm)) {
        fprintf(stderr, "Aplay:params setting failed\n");
        pcm_close(pcm);
        return -errno;
    }

    if (!pcm_flag) {
       if (pcm_prepare(pcm)) {
          fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
          pcm_close(pcm);
          return -errno;
       }
        while(1);
    }

    if (flags & PCM_MMAP) {
        if (mmap_buffer(pcm)) {
             fprintf(stderr, "Aplay:params setting failed\n");
             pcm_close(pcm);
             return -errno;
        }
       if (pcm_prepare(pcm)) {
          fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
          pcm_close(pcm);
          return -errno;
       }
        bufsize = pcm->period_size;
        if (debug)
          fprintf(stderr, "Aplay:bufsize = %d\n", bufsize);
        data = calloc(1, bufsize);
        if (!data) {
           fprintf(stderr, "Aplay:could not allocate %d bytes\n", count);
           pcm_close(pcm);
           return -ENOMEM;
        }

        pfd[0].fd = pcm->fd;
        pfd[0].events = POLLOUT;
        while (read(fd, data, bufsize) == bufsize) {
            x.buf = data;
            x.frames = (pcm->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4);
            frames = x.frames;

            for (;;) {
                if (!pcm->running) {
                    if (pcm_prepare(pcm))
                        return --errno;
                    pcm->running = 1;
                    start = 0;
                }
                pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
                err = sync_ptr(pcm);
                if (err == EPIPE) {
                     fprintf(stderr, "Aplay:Failed in sync_ptr \n");
                     /* we failed to make our window -- try to restart */
                     pcm->underruns++;
                     pcm->running = 0;
                     continue;
                }
                avail = pcm_avail(pcm);
                if (debug)
                    fprintf(stderr, "Aplay:avail 1 = %d frames = %d\n",avail, frames);
                if (avail < 0)
                    return avail;
                if (avail < pcm->sw_p->avail_min) {
                    poll(pfd, nfds, TIMEOUT_INFINITE);
                    continue;
                }
                if (x.frames > avail)
                    frames = avail;
                if (debug) {
                    fprintf(stderr, "Aplay:avail = %d frames = %d\n",avail, frames);
                    fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  pcm->buffer_size %d  sync_ptr->c.control.appl_ptr %ld\n",
                            pcm->sync_ptr->s.status.hw_ptr,
                            pcm->buffer_size,
                            pcm->sync_ptr->c.control.appl_ptr);
                }
                err = mmap_transfer(pcm, data , offset, frames);
                if (err == EPIPE) {
                    fprintf(stderr, "Aplay:Failed in mmap_transfer \n");
                    /* we failed to make our window -- try to restart */
                    pcm->underruns++;
                    pcm->running = 0;
                    continue;
                }
                x.frames -= frames;
                pcm->sync_ptr->c.control.appl_ptr += frames;
                pcm->sync_ptr->flags = 0;

                err = sync_ptr(pcm);
                if (err == EPIPE) {
                    fprintf(stderr, "Aplay:Failed in sync_ptr 2 \n");
                    /* we failed to make our window -- try to restart */
                    pcm->underruns++;
                    pcm->running = 0;
                    continue;
                }
                if (debug) {
                    fprintf(stderr, "Aplay:sync_ptr 2 \n");
                    fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld  pcm->buffer_size %d  sync_ptr->c.control.appl_ptr %ld\n",
                            pcm->sync_ptr->s.status.hw_ptr,
                            pcm->buffer_size,
                            pcm->sync_ptr->c.control.appl_ptr);
                }
                if (pcm->sync_ptr->c.control.appl_ptr >= pcm->sw_p->start_threshold) {
                    if(start)
                        goto xyz;
                    if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
                        err = -errno;
                        if (errno == EPIPE) {
                            fprintf(stderr, "Aplay:Failed in SNDRV_PCM_IOCTL_START\n");
                            /* we failed to make our window -- try to restart */
                            pcm->underruns++;
                            pcm->running = 0;
                            continue;
                        } else {
                            fprintf(stderr, "Aplay:Error no %d \n", errno);
                            return -errno;
                        }
                    } else
                        start = 1;
                }
xyz:
                offset += frames;
                break;
            }
        }
    } else {
       if (pcm_prepare(pcm)) {
          fprintf(stderr, "Aplay:Failed in pcm_prepare\n");
          pcm_close(pcm);
          return -errno;
       }
        bufsize = pcm->period_size;
        if (debug)
          fprintf(stderr, "Aplay:bufsize = %d\n", bufsize);
        data = calloc(1, bufsize);
        if (!data) {
            fprintf(stderr, "Aplay:could not allocate %d bytes\n", count);
            pcm_close(pcm);
            return -ENOMEM;
        }

        while (read(fd, data, bufsize) == bufsize) {
            if (pcm_write(pcm, data, bufsize)){
                fprintf(stderr, "Aplay: pcm_write failed\n");
                break;
            }
        }
    }
    fprintf(stderr, "Aplay: Done playing\n");
    free(data);
    pcm_close(pcm);
    return 0;
}