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