Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2 * Helper functions for indirect PCM data transfer
  3 *
  4 *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
  5 *                   Jaroslav Kysela <perex@perex.cz>
  6 *
  7 *   This program is free software; you can redistribute it and/or modify
  8 *   it under the terms of the GNU General Public License as published by
  9 *   the Free Software Foundation; either version 2 of the License, or
 10 *   (at your option) any later version.
 11 *
 12 *   This program is distributed in the hope that it will be useful,
 13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 *   GNU General Public License for more details.
 16 *
 17 *   You should have received a copy of the GNU General Public License
 18 *   along with this program; if not, write to the Free Software
 19 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 20 */
 21
 22#ifndef __SOUND_PCM_INDIRECT_H
 23#define __SOUND_PCM_INDIRECT_H
 24
 25#include <sound/pcm.h>
 26
 27struct snd_pcm_indirect {
 28	unsigned int hw_buffer_size;	/* Byte size of hardware buffer */
 29	unsigned int hw_queue_size;	/* Max queue size of hw buffer (0 = buffer size) */
 30	unsigned int hw_data;	/* Offset to next dst (or src) in hw ring buffer */
 31	unsigned int hw_io;	/* Ring buffer hw pointer */
 32	int hw_ready;		/* Bytes ready for play (or captured) in hw ring buffer */
 33	unsigned int sw_buffer_size;	/* Byte size of software buffer */
 34	unsigned int sw_data;	/* Offset to next dst (or src) in sw ring buffer */
 35	unsigned int sw_io;	/* Current software pointer in bytes */
 36	int sw_ready;		/* Bytes ready to be transferred to/from hw */
 37	snd_pcm_uframes_t appl_ptr;	/* Last seen appl_ptr */
 38};
 39
 40typedef void (*snd_pcm_indirect_copy_t)(struct snd_pcm_substream *substream,
 41					struct snd_pcm_indirect *rec, size_t bytes);
 42
 43/*
 44 * helper function for playback ack callback
 45 */
 46static inline void
 47snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream,
 48				   struct snd_pcm_indirect *rec,
 49				   snd_pcm_indirect_copy_t copy)
 50{
 51	struct snd_pcm_runtime *runtime = substream->runtime;
 52	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
 53	snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
 54	int qsize;
 55
 56	if (diff) {
 57		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
 58			diff += runtime->boundary;
 59		rec->sw_ready += (int)frames_to_bytes(runtime, diff);
 60		rec->appl_ptr = appl_ptr;
 61	}
 62	qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
 63	while (rec->hw_ready < qsize && rec->sw_ready > 0) {
 64		unsigned int hw_to_end = rec->hw_buffer_size - rec->hw_data;
 65		unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
 66		unsigned int bytes = qsize - rec->hw_ready;
 67		if (rec->sw_ready < (int)bytes)
 68			bytes = rec->sw_ready;
 69		if (hw_to_end < bytes)
 70			bytes = hw_to_end;
 71		if (sw_to_end < bytes)
 72			bytes = sw_to_end;
 73		if (! bytes)
 74			break;
 75		copy(substream, rec, bytes);
 76		rec->hw_data += bytes;
 77		if (rec->hw_data == rec->hw_buffer_size)
 78			rec->hw_data = 0;
 79		rec->sw_data += bytes;
 80		if (rec->sw_data == rec->sw_buffer_size)
 81			rec->sw_data = 0;
 82		rec->hw_ready += bytes;
 83		rec->sw_ready -= bytes;
 84	}
 85}
 86
 87/*
 88 * helper function for playback pointer callback
 89 * ptr = current byte pointer
 90 */
 91static inline snd_pcm_uframes_t
 92snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream,
 93				  struct snd_pcm_indirect *rec, unsigned int ptr)
 94{
 95	int bytes = ptr - rec->hw_io;
 96	if (bytes < 0)
 97		bytes += rec->hw_buffer_size;
 98	rec->hw_io = ptr;
 99	rec->hw_ready -= bytes;
100	rec->sw_io += bytes;
101	if (rec->sw_io >= rec->sw_buffer_size)
102		rec->sw_io -= rec->sw_buffer_size;
103	if (substream->ops->ack)
104		substream->ops->ack(substream);
105	return bytes_to_frames(substream->runtime, rec->sw_io);
106}
107
108
109/*
110 * helper function for capture ack callback
111 */
112static inline void
113snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
114				  struct snd_pcm_indirect *rec,
115				  snd_pcm_indirect_copy_t copy)
116{
117	struct snd_pcm_runtime *runtime = substream->runtime;
118	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
119	snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
120
121	if (diff) {
122		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
123			diff += runtime->boundary;
124		rec->sw_ready -= frames_to_bytes(runtime, diff);
125		rec->appl_ptr = appl_ptr;
126	}
127	while (rec->hw_ready > 0 && 
128	       rec->sw_ready < (int)rec->sw_buffer_size) {
129		size_t hw_to_end = rec->hw_buffer_size - rec->hw_data;
130		size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
131		size_t bytes = rec->sw_buffer_size - rec->sw_ready;
132		if (rec->hw_ready < (int)bytes)
133			bytes = rec->hw_ready;
134		if (hw_to_end < bytes)
135			bytes = hw_to_end;
136		if (sw_to_end < bytes)
137			bytes = sw_to_end;
138		if (! bytes)
139			break;
140		copy(substream, rec, bytes);
141		rec->hw_data += bytes;
142		if ((int)rec->hw_data == rec->hw_buffer_size)
143			rec->hw_data = 0;
144		rec->sw_data += bytes;
145		if (rec->sw_data == rec->sw_buffer_size)
146			rec->sw_data = 0;
147		rec->hw_ready -= bytes;
148		rec->sw_ready += bytes;
149	}
150}
151
152/*
153 * helper function for capture pointer callback,
154 * ptr = current byte pointer
155 */
156static inline snd_pcm_uframes_t
157snd_pcm_indirect_capture_pointer(struct snd_pcm_substream *substream,
158				 struct snd_pcm_indirect *rec, unsigned int ptr)
159{
160	int qsize;
161	int bytes = ptr - rec->hw_io;
162	if (bytes < 0)
163		bytes += rec->hw_buffer_size;
164	rec->hw_io = ptr;
165	rec->hw_ready += bytes;
166	qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
167	if (rec->hw_ready > qsize)
168		return SNDRV_PCM_POS_XRUN;
169	rec->sw_io += bytes;
170	if (rec->sw_io >= rec->sw_buffer_size)
171		rec->sw_io -= rec->sw_buffer_size;
172	if (substream->ops->ack)
173		substream->ops->ack(substream);
174	return bytes_to_frames(substream->runtime, rec->sw_io);
175}
176
177#endif /* __SOUND_PCM_INDIRECT_H */
v3.15
  1/*
  2 * Helper functions for indirect PCM data transfer
  3 *
  4 *  Copyright (c) by Takashi Iwai <tiwai@suse.de>
  5 *                   Jaroslav Kysela <perex@perex.cz>
  6 *
  7 *   This program is free software; you can redistribute it and/or modify
  8 *   it under the terms of the GNU General Public License as published by
  9 *   the Free Software Foundation; either version 2 of the License, or
 10 *   (at your option) any later version.
 11 *
 12 *   This program is distributed in the hope that it will be useful,
 13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15 *   GNU General Public License for more details.
 16 *
 17 *   You should have received a copy of the GNU General Public License
 18 *   along with this program; if not, write to the Free Software
 19 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 20 */
 21
 22#ifndef __SOUND_PCM_INDIRECT_H
 23#define __SOUND_PCM_INDIRECT_H
 24
 25#include <sound/pcm.h>
 26
 27struct snd_pcm_indirect {
 28	unsigned int hw_buffer_size;	/* Byte size of hardware buffer */
 29	unsigned int hw_queue_size;	/* Max queue size of hw buffer (0 = buffer size) */
 30	unsigned int hw_data;	/* Offset to next dst (or src) in hw ring buffer */
 31	unsigned int hw_io;	/* Ring buffer hw pointer */
 32	int hw_ready;		/* Bytes ready for play (or captured) in hw ring buffer */
 33	unsigned int sw_buffer_size;	/* Byte size of software buffer */
 34	unsigned int sw_data;	/* Offset to next dst (or src) in sw ring buffer */
 35	unsigned int sw_io;	/* Current software pointer in bytes */
 36	int sw_ready;		/* Bytes ready to be transferred to/from hw */
 37	snd_pcm_uframes_t appl_ptr;	/* Last seen appl_ptr */
 38};
 39
 40typedef void (*snd_pcm_indirect_copy_t)(struct snd_pcm_substream *substream,
 41					struct snd_pcm_indirect *rec, size_t bytes);
 42
 43/*
 44 * helper function for playback ack callback
 45 */
 46static inline void
 47snd_pcm_indirect_playback_transfer(struct snd_pcm_substream *substream,
 48				   struct snd_pcm_indirect *rec,
 49				   snd_pcm_indirect_copy_t copy)
 50{
 51	struct snd_pcm_runtime *runtime = substream->runtime;
 52	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
 53	snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
 54	int qsize;
 55
 56	if (diff) {
 57		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
 58			diff += runtime->boundary;
 59		rec->sw_ready += (int)frames_to_bytes(runtime, diff);
 60		rec->appl_ptr = appl_ptr;
 61	}
 62	qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
 63	while (rec->hw_ready < qsize && rec->sw_ready > 0) {
 64		unsigned int hw_to_end = rec->hw_buffer_size - rec->hw_data;
 65		unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
 66		unsigned int bytes = qsize - rec->hw_ready;
 67		if (rec->sw_ready < (int)bytes)
 68			bytes = rec->sw_ready;
 69		if (hw_to_end < bytes)
 70			bytes = hw_to_end;
 71		if (sw_to_end < bytes)
 72			bytes = sw_to_end;
 73		if (! bytes)
 74			break;
 75		copy(substream, rec, bytes);
 76		rec->hw_data += bytes;
 77		if (rec->hw_data == rec->hw_buffer_size)
 78			rec->hw_data = 0;
 79		rec->sw_data += bytes;
 80		if (rec->sw_data == rec->sw_buffer_size)
 81			rec->sw_data = 0;
 82		rec->hw_ready += bytes;
 83		rec->sw_ready -= bytes;
 84	}
 85}
 86
 87/*
 88 * helper function for playback pointer callback
 89 * ptr = current byte pointer
 90 */
 91static inline snd_pcm_uframes_t
 92snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream,
 93				  struct snd_pcm_indirect *rec, unsigned int ptr)
 94{
 95	int bytes = ptr - rec->hw_io;
 96	if (bytes < 0)
 97		bytes += rec->hw_buffer_size;
 98	rec->hw_io = ptr;
 99	rec->hw_ready -= bytes;
100	rec->sw_io += bytes;
101	if (rec->sw_io >= rec->sw_buffer_size)
102		rec->sw_io -= rec->sw_buffer_size;
103	if (substream->ops->ack)
104		substream->ops->ack(substream);
105	return bytes_to_frames(substream->runtime, rec->sw_io);
106}
107
108
109/*
110 * helper function for capture ack callback
111 */
112static inline void
113snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
114				  struct snd_pcm_indirect *rec,
115				  snd_pcm_indirect_copy_t copy)
116{
117	struct snd_pcm_runtime *runtime = substream->runtime;
118	snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
119	snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
120
121	if (diff) {
122		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
123			diff += runtime->boundary;
124		rec->sw_ready -= frames_to_bytes(runtime, diff);
125		rec->appl_ptr = appl_ptr;
126	}
127	while (rec->hw_ready > 0 && 
128	       rec->sw_ready < (int)rec->sw_buffer_size) {
129		size_t hw_to_end = rec->hw_buffer_size - rec->hw_data;
130		size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
131		size_t bytes = rec->sw_buffer_size - rec->sw_ready;
132		if (rec->hw_ready < (int)bytes)
133			bytes = rec->hw_ready;
134		if (hw_to_end < bytes)
135			bytes = hw_to_end;
136		if (sw_to_end < bytes)
137			bytes = sw_to_end;
138		if (! bytes)
139			break;
140		copy(substream, rec, bytes);
141		rec->hw_data += bytes;
142		if ((int)rec->hw_data == rec->hw_buffer_size)
143			rec->hw_data = 0;
144		rec->sw_data += bytes;
145		if (rec->sw_data == rec->sw_buffer_size)
146			rec->sw_data = 0;
147		rec->hw_ready -= bytes;
148		rec->sw_ready += bytes;
149	}
150}
151
152/*
153 * helper function for capture pointer callback,
154 * ptr = current byte pointer
155 */
156static inline snd_pcm_uframes_t
157snd_pcm_indirect_capture_pointer(struct snd_pcm_substream *substream,
158				 struct snd_pcm_indirect *rec, unsigned int ptr)
159{
160	int qsize;
161	int bytes = ptr - rec->hw_io;
162	if (bytes < 0)
163		bytes += rec->hw_buffer_size;
164	rec->hw_io = ptr;
165	rec->hw_ready += bytes;
166	qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
167	if (rec->hw_ready > qsize)
168		return SNDRV_PCM_POS_XRUN;
169	rec->sw_io += bytes;
170	if (rec->sw_io >= rec->sw_buffer_size)
171		rec->sw_io -= rec->sw_buffer_size;
172	if (substream->ops->ack)
173		substream->ops->ack(substream);
174	return bytes_to_frames(substream->runtime, rec->sw_io);
175}
176
177#endif /* __SOUND_PCM_INDIRECT_H */