aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/pcm.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/pcm.c b/src/pcm.c
index 24ab333..a45ce75 100644
--- a/src/pcm.c
+++ b/src/pcm.c
@@ -156,15 +156,26 @@ static void param_init(struct snd_pcm_hw_params *p)
#define PCM_ERROR_MAX 128
+/** A PCM handle.
+ * @ingroup tinyalsa-pcm
+ */
struct pcm {
+ /** The PCM's file descriptor */
int fd;
+ /** Flags that were passed to @ref pcm_open */
unsigned int flags;
+ /** Whether the PCM is running or not */
int running:1;
+ /** Whether or not the PCM has been prepared */
int prepared:1;
+ /** The number of underruns that have occured */
int underruns;
+ /** Size of the buffer */
unsigned int buffer_size;
unsigned int boundary;
+ /** Description of the last error that occured */
char error[PCM_ERROR_MAX];
+ /** Configuration that was passed to @ref pcm_open */
struct pcm_config config;
struct snd_pcm_mmap_status *mmap_status;
struct snd_pcm_mmap_control *mmap_control;
@@ -175,21 +186,40 @@ struct pcm {
unsigned int subdevice;
};
+/** Gets the buffer size of the PCM.
+ * @param pcm A PCM handle.
+ * @return The buffer size of the PCM.
+ * @ingroup tinyalsa-pcm
+ */
unsigned int pcm_get_buffer_size(struct pcm *pcm)
{
return pcm->buffer_size;
}
+/** Gets the file descriptor of the PCM.
+ * Useful for extending functionality of the PCM when needed.
+ * @return The file descriptor of the PCM.
+ * @ingroup tinyalsa-pcm
+ */
int pcm_get_file_descriptor(struct pcm *pcm)
{
return pcm->fd;
}
+/** Gets the error message for the last error that occured.
+ * If no error occured and this function is called, the results are undefined.
+ * @param pcm A PCM handle.
+ * @return The error message of the last error that occured.
+ * @ingroup tinyalsa-pcm
+ */
const char* pcm_get_error(struct pcm *pcm)
{
return pcm->error;
}
+/** Gets the subdevice on which the pcm has been opened.
+ * @param pcm A PCM handle.
+ * @return The subdevice on which the pcm has been opened */
unsigned int pcm_get_subdevice(struct pcm *pcm)
{
return pcm->subdevice;
@@ -241,6 +271,11 @@ static unsigned int pcm_format_to_alsa(enum pcm_format format)
};
}
+/** Determines the number of bits occupied by a @ref pcm_format.
+ * @param format A PCM format.
+ * @return The number of bits associated with @p format
+ * @ingroup tinyalsa-pcm
+ */
unsigned int pcm_format_to_bits(enum pcm_format format)
{
switch (format) {
@@ -261,12 +296,24 @@ unsigned int pcm_format_to_bits(enum pcm_format format)
};
}
+/** Determines how many frames of a PCM can fit into a number of bytes.
+ * @param pcm A PCM handle.
+ * @param bytes The number of bytes.
+ * @return The number of frames that may fit into @p bytes
+ * @ingroup tinyalsa-pcm
+ */
unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes)
{
return bytes / (pcm->config.channels *
(pcm_format_to_bits(pcm->config.format) >> 3));
}
+/** Determines how many bytes are occupied by a number of frames of a PCM.
+ * @param pcm A PCM handle.
+ * @param frames The number of frames of a PCM.
+ * @return The bytes occupied by @p frames.
+ * @ingroup tinyalsa-pcm
+ */
unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames)
{
return frames * pcm->config.channels *
@@ -381,6 +428,17 @@ static int pcm_mmap_transfer_areas(struct pcm *pcm, char *buf,
return count;
}
+/** Returns available frames in pcm buffer and corresponding time stamp.
+ * The clock is CLOCK_MONOTONIC if flag @ref PCM_MONOTONIC was specified in @ref pcm_open,
+ * otherwise the clock is CLOCK_REALTIME.
+ * For an input stream, frames available are frames ready for the application to read.
+ * For an output stream, frames available are the number of empty frames available for the application to write.
+ * Only available for PCMs opened with the @ref PCM_MMAP flag.
+ * @param pcm A PCM handle.
+ * @param avail The number of available frames
+ * @param tstamp The timestamp
+ * @return On success, zero is returned; on failure, negative one.
+ */
int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail,
struct timespec *tstamp)
{
@@ -417,6 +475,16 @@ int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail,
return 0;
}
+/** Writes audio samples to PCM.
+ * If the PCM has not been started, it is started in this function.
+ * This function is only valid for PCMs opened with the @ref PCM_OUT flag.
+ * This function is not valid for PCMs opened with the @ref PCM_MMAP flag.
+ * @param pcm A PCM handle.
+ * @param data The audio sample array
+ * @param count The number of bytes occupied by the sample array.
+ * @return On success, this function returns zero; otherwise, a negative number.
+ * @ingroup tinyalsa-pcm
+ */
int pcm_write(struct pcm *pcm, const void *data, unsigned int count)
{
struct snd_xferi x;
@@ -456,6 +524,16 @@ int pcm_write(struct pcm *pcm, const void *data, unsigned int count)
}
}
+/** Reads audio samples from PCM.
+ * If the PCM has not been started, it is started in this function.
+ * This function is only valid for PCMs opened with the @ref PCM_IN flag.
+ * This function is not valid for PCMs opened with the @ref PCM_MMAP flag.
+ * @param pcm A PCM handle.
+ * @param data The audio sample array
+ * @param count The number of bytes occupied by the sample array.
+ * @return On success, this function returns zero; otherwise, a negative number.
+ * @ingroup tinyalsa-pcm
+ */
int pcm_read(struct pcm *pcm, void *data, unsigned int count)
{
struct snd_xferi x;
@@ -492,6 +570,18 @@ static struct pcm bad_pcm = {
.fd = -1,
};
+/** Gets the hardware parameters of a PCM, without created a PCM handle.
+ * @param card The card of the PCM.
+ * The default card is zero.
+ * @param device The device of the PCM.
+ * The default device is zero.
+ * @param flags Specifies whether the PCM is an input or output.
+ * May be one of the following:
+ * - @ref PCM_IN
+ * - @ref PCM_OUT
+ * @return On success, the hardware parameters of the PCM; on failure, NULL.
+ * @ingroup tinyalsa-pcm
+ */
struct pcm_params *pcm_params_get(unsigned int card, unsigned int device,
unsigned int flags)
{
@@ -530,6 +620,11 @@ err_open:
return NULL;
}
+/** Frees the hardware parameters returned by @ref pcm_params_open.
+ * @param pcm_params Hardware parameters of a PCM.
+ * May be NULL.
+ * @ingroup tinyalsa-pcm
+ */
void pcm_params_free(struct pcm_params *pcm_params)
{
struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params;
@@ -589,6 +684,13 @@ static int pcm_param_to_alsa(enum pcm_param param)
}
}
+/** Gets a mask from a PCM's hardware parameters.
+ * @param pcm_params A PCM's hardware parameters.
+ * @param param The parameter to get.
+ * @return If @p pcm_params is NULL or @p param is not a mask, NULL is returned.
+ * Otherwise, the mask associated with @p param is returned.
+ * @ingroup tinyalsa-pcm
+ */
struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params,
enum pcm_param param)
{
@@ -638,6 +740,12 @@ unsigned int pcm_params_get_max(struct pcm_params *pcm_params,
return param_get_max(params, p);
}
+/** Closes a PCM returned by @ref pcm_open.
+ * @param pcm A PCM returned by @ref pcm_open.
+ * May not be NULL.
+ * @return Always returns zero.
+ * @ingroup tinyalsa-pcm
+ */
int pcm_close(struct pcm *pcm)
{
if (pcm == &bad_pcm)
@@ -660,6 +768,23 @@ int pcm_close(struct pcm *pcm)
return 0;
}
+/** Opens a PCM.
+ * @param card The card that the pcm belongs to.
+ * The default card is zero.
+ * @param device The device that the pcm belongs to.
+ * The default device is zero.
+ * @param flags Specify characteristics and functionality about the pcm.
+ * May be a bitwise AND of the following:
+ * - @ref PCM_IN
+ * - @ref PCM_OUT
+ * - @ref PCM_MMAP
+ * - @ref PCM_NOIRQ
+ * - @ref PCM_MONOTONIC
+ * @param config The hardware and software parameters to open the PCM with.
+ * @returns On success, returns an initialized pcm, ready for reading or writing.
+ * On error, returns NULL.
+ * @ingroup tinyalsa-pcm
+ */
struct pcm *pcm_open(unsigned int card, unsigned int device,
unsigned int flags, struct pcm_config *config)
{
@@ -814,11 +939,22 @@ fail_close:
return pcm;
}
+/** Checks if a PCM file has been opened without error.
+ * @param pcm A PCM handle.
+ * @return If a PCM's file descriptor is not valid, it returns zero.
+ * Otherwise, the function returns one.
+ * @ingroup tinyalsa-pcm
+ */
int pcm_is_ready(struct pcm *pcm)
{
return pcm->fd >= 0;
}
+/** Prepares a PCM, if it has not been prepared already.
+ * @param pcm A PCM handle.
+ * @return On success, zero; on failure, a negative number.
+ * @ingroup tinyalsa-pcm
+ */
int pcm_prepare(struct pcm *pcm)
{
if (pcm->prepared)
@@ -831,6 +967,13 @@ int pcm_prepare(struct pcm *pcm)
return 0;
}
+/** Starts a PCM.
+ * If the PCM has not been prepared,
+ * it is prepared in this function.
+ * @param pcm A PCM handle.
+ * @return On success, zero; on failure, a negative number.
+ * @ingroup tinyalsa-pcm
+ */
int pcm_start(struct pcm *pcm)
{
int prepare_error = pcm_prepare(pcm);
@@ -847,6 +990,11 @@ int pcm_start(struct pcm *pcm)
return 0;
}
+/** Stops a PCM.
+ * @param pcm A PCM handle.
+ * @return On success, zero; on failure, a negative number.
+ * @ingroup tinyalsa-pcm
+ */
int pcm_stop(struct pcm *pcm)
{
if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0)
@@ -1095,3 +1243,4 @@ long pcm_get_delay(struct pcm *pcm)
return pcm->pcm_delay;
}
+