Advertisement
Guest User

pcm-indirect.h

a guest
May 6th, 2015
248
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.46 KB | None | 0 0
  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.  
  27. struct 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.  
  40. typedef 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.  */
  46. static inline void
  47. snd_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.        
  64.     // xrun disabled.. typically done by dmix plugin
  65.     if( runtime->stop_threshold == runtime->boundary )  {
  66.            unsigned int bytes = rec->sw_ready;
  67.            if (bytes)
  68.            {
  69.            copy(substream, rec, bytes);
  70.            rec->hw_data += bytes;
  71.            if (rec->hw_data == rec->hw_buffer_size)
  72.             rec->hw_data = 0;
  73.            rec->sw_data += bytes;
  74.            if (rec->sw_data == rec->sw_buffer_size)
  75.             rec->sw_data = 0;
  76.            rec->hw_ready += bytes;
  77.            rec->sw_ready -= bytes;
  78.                
  79.            }
  80.            return;
  81.     }
  82.     while (rec->hw_ready < qsize && rec->sw_ready > 0) {
  83.         unsigned int hw_to_end = rec->hw_buffer_size - rec->hw_data;
  84.         unsigned int sw_to_end = rec->sw_buffer_size - rec->sw_data;
  85.         unsigned int bytes = qsize - rec->hw_ready;
  86.         if (rec->sw_ready < (int)bytes)
  87.             bytes = rec->sw_ready;
  88.         if (hw_to_end < bytes)
  89.             bytes = hw_to_end;
  90.         if (sw_to_end < bytes)
  91.             bytes = sw_to_end;
  92.         if (! bytes)
  93.             break;
  94.         copy(substream, rec, bytes);
  95.         rec->hw_data += bytes;
  96.         if (rec->hw_data == rec->hw_buffer_size)
  97.             rec->hw_data = 0;
  98.         rec->sw_data += bytes;
  99.         if (rec->sw_data == rec->sw_buffer_size)
  100.             rec->sw_data = 0;
  101.         rec->hw_ready += bytes;
  102.         rec->sw_ready -= bytes;
  103.     }
  104. }
  105.  
  106. /*
  107.  * helper function for playback pointer callback
  108.  * ptr = current byte pointer
  109.  */
  110. static inline snd_pcm_uframes_t
  111. snd_pcm_indirect_playback_pointer(struct snd_pcm_substream *substream,
  112.                   struct snd_pcm_indirect *rec, unsigned int ptr)
  113. {
  114.     int bytes = ptr - rec->hw_io;
  115.     if (bytes < 0)
  116.         bytes += rec->hw_buffer_size;
  117.     if( substream->runtime->stop_threshold == substream->runtime->boundary )  // xrun disabled.. typically done by dmix plugin
  118.     {
  119.             rec->sw_ready = bytes;
  120.        
  121.     }
  122.     rec->hw_io = ptr;
  123.     rec->hw_ready -= bytes;
  124.     rec->sw_io += bytes;
  125.     if (rec->sw_io >= rec->sw_buffer_size)
  126.         rec->sw_io -= rec->sw_buffer_size;
  127.     if (substream->ops->ack)
  128.         substream->ops->ack(substream);
  129.     return bytes_to_frames(substream->runtime, rec->sw_io);
  130. }
  131.  
  132.  
  133. /*
  134.  * helper function for capture ack callback
  135.  */
  136. static inline void
  137. snd_pcm_indirect_capture_transfer(struct snd_pcm_substream *substream,
  138.                   struct snd_pcm_indirect *rec,
  139.                   snd_pcm_indirect_copy_t copy)
  140. {
  141.     struct snd_pcm_runtime *runtime = substream->runtime;
  142.     snd_pcm_uframes_t appl_ptr = runtime->control->appl_ptr;
  143.     snd_pcm_sframes_t diff = appl_ptr - rec->appl_ptr;
  144.  
  145.     if (diff) {
  146.         if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
  147.             diff += runtime->boundary;
  148.         rec->sw_ready -= frames_to_bytes(runtime, diff);
  149.         rec->appl_ptr = appl_ptr;
  150.     }
  151.     while (rec->hw_ready > 0 &&
  152.            rec->sw_ready < (int)rec->sw_buffer_size) {
  153.         size_t hw_to_end = rec->hw_buffer_size - rec->hw_data;
  154.         size_t sw_to_end = rec->sw_buffer_size - rec->sw_data;
  155.         size_t bytes = rec->sw_buffer_size - rec->sw_ready;
  156.         if (rec->hw_ready < (int)bytes)
  157.             bytes = rec->hw_ready;
  158.         if (hw_to_end < bytes)
  159.             bytes = hw_to_end;
  160.         if (sw_to_end < bytes)
  161.             bytes = sw_to_end;
  162.         if (! bytes)
  163.             break;
  164.         copy(substream, rec, bytes);
  165.         rec->hw_data += bytes;
  166.         if ((int)rec->hw_data == rec->hw_buffer_size)
  167.             rec->hw_data = 0;
  168.         rec->sw_data += bytes;
  169.         if (rec->sw_data == rec->sw_buffer_size)
  170.             rec->sw_data = 0;
  171.         rec->hw_ready -= bytes;
  172.         rec->sw_ready += bytes;
  173.     }
  174. }
  175.  
  176. /*
  177.  * helper function for capture pointer callback,
  178.  * ptr = current byte pointer
  179.  */
  180. static inline snd_pcm_uframes_t
  181. snd_pcm_indirect_capture_pointer(struct snd_pcm_substream *substream,
  182.                  struct snd_pcm_indirect *rec, unsigned int ptr)
  183. {
  184.     int qsize;
  185.     int bytes = ptr - rec->hw_io;
  186.     if (bytes < 0)
  187.         bytes += rec->hw_buffer_size;
  188.     rec->hw_io = ptr;
  189.     rec->hw_ready += bytes;
  190.     qsize = rec->hw_queue_size ? rec->hw_queue_size : rec->hw_buffer_size;
  191.     if (rec->hw_ready > qsize)
  192.         return SNDRV_PCM_POS_XRUN;
  193.     rec->sw_io += bytes;
  194.     if (rec->sw_io >= rec->sw_buffer_size)
  195.         rec->sw_io -= rec->sw_buffer_size;
  196.     if (substream->ops->ack)
  197.         substream->ops->ack(substream);
  198.     return bytes_to_frames(substream->runtime, rec->sw_io);
  199. }
  200.  
  201. #endif /* __SOUND_PCM_INDIRECT_H */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement