1 /* 2 * $Id: pa_ringbuffer.c 1421 2009-11-18 16:09:05Z bjornroche $ 3 * Portable Audio I/O Library 4 * Ring Buffer utility. 5 * 6 * Author: Phil Burk, http://www.softsynth.com 7 * modified for SMP safety on Mac OS X by Bjorn Roche 8 * modified for SMP safety on Linux by Leland Lucius 9 * also, allowed for const where possible 10 * modified for multiple-byte-sized data elements by Sven Fischer 11 * 12 * Note that this is safe only for a single-thread reader and a 13 * single-thread writer. 14 * 15 * This program uses the PortAudio Portable Audio Library. 16 * For more information see: http://www.portaudio.com 17 * Copyright (c) 1999-2000 Ross Bencina and Phil Burk 18 * 19 * Permission is hereby granted, free of charge, to any person obtaining 20 * a copy of this software and associated documentation files 21 * (the "Software"), to deal in the Software without restriction, 22 * including without limitation the rights to use, copy, modify, merge, 23 * publish, distribute, sublicense, and/or sell copies of the Software, 24 * and to permit persons to whom the Software is furnished to do so, 25 * subject to the following conditions: 26 * 27 * The above copyright notice and this permission notice shall be 28 * included in all copies or substantial portions of the Software. 29 * 30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 31 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 32 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 33 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 34 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 35 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 36 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 37 */ 38 39 /* 40 * The text above constitutes the entire PortAudio license; however, 41 * the PortAudio community also makes the following non-binding requests: 42 * 43 * Any person wishing to distribute modifications to the Software is 44 * requested to send the modifications to the original developer so that 45 * they can be incorporated into the canonical version. It is also 46 * requested that these non-binding requests be included along with the 47 * license above. 48 */ 49 50 /** 51 @file 52 @ingroup common_src 53 */ 54 55 #include <math.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include "webrtc/modules/audio_device/mac/portaudio/pa_memorybarrier.h" 60 #include "webrtc/modules/audio_device/mac/portaudio/pa_ringbuffer.h" 61 62 /*************************************************************************** 63 * Initialize FIFO. 64 * elementCount must be power of 2, returns -1 if not. 65 */ 66 PaRingBufferSize PaUtil_InitializeRingBuffer(PaUtilRingBuffer* rbuf, 67 PaRingBufferSize elementSizeBytes, 68 PaRingBufferSize elementCount, 69 void* dataPtr) { 70 if( ((elementCount-1) & elementCount) != 0) return -1; /* Not Power of two. */ 71 rbuf->bufferSize = elementCount; 72 rbuf->buffer = (char *)dataPtr; 73 PaUtil_FlushRingBuffer( rbuf ); 74 rbuf->bigMask = (elementCount*2)-1; 75 rbuf->smallMask = (elementCount)-1; 76 rbuf->elementSizeBytes = elementSizeBytes; 77 return 0; 78 } 79 80 /*************************************************************************** 81 ** Return number of elements available for reading. */ 82 PaRingBufferSize PaUtil_GetRingBufferReadAvailable( PaUtilRingBuffer *rbuf ) 83 { 84 PaUtil_ReadMemoryBarrier(); 85 return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask ); 86 } 87 /*************************************************************************** 88 ** Return number of elements available for writing. */ 89 PaRingBufferSize PaUtil_GetRingBufferWriteAvailable( PaUtilRingBuffer *rbuf ) 90 { 91 /* Since we are calling PaUtil_GetRingBufferReadAvailable, we don't need an aditional MB */ 92 return ( rbuf->bufferSize - PaUtil_GetRingBufferReadAvailable(rbuf)); 93 } 94 95 /*************************************************************************** 96 ** Clear buffer. Should only be called when buffer is NOT being read. */ 97 void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf ) 98 { 99 rbuf->writeIndex = rbuf->readIndex = 0; 100 } 101 102 /*************************************************************************** 103 ** Get address of region(s) to which we can write data. 104 ** If the region is contiguous, size2 will be zero. 105 ** If non-contiguous, size2 will be the size of second region. 106 ** Returns room available to be written or elementCount, whichever is smaller. 107 */ 108 PaRingBufferSize PaUtil_GetRingBufferWriteRegions(PaUtilRingBuffer* rbuf, 109 PaRingBufferSize elementCount, 110 void** dataPtr1, 111 PaRingBufferSize* sizePtr1, 112 void** dataPtr2, 113 PaRingBufferSize* sizePtr2) { 114 PaRingBufferSize index; 115 PaRingBufferSize available = PaUtil_GetRingBufferWriteAvailable( rbuf ); 116 if( elementCount > available ) elementCount = available; 117 /* Check to see if write is not contiguous. */ 118 index = rbuf->writeIndex & rbuf->smallMask; 119 if( (index + elementCount) > rbuf->bufferSize ) 120 { 121 /* Write data in two blocks that wrap the buffer. */ 122 PaRingBufferSize firstHalf = rbuf->bufferSize - index; 123 *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; 124 *sizePtr1 = firstHalf; 125 *dataPtr2 = &rbuf->buffer[0]; 126 *sizePtr2 = elementCount - firstHalf; 127 } 128 else 129 { 130 *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; 131 *sizePtr1 = elementCount; 132 *dataPtr2 = NULL; 133 *sizePtr2 = 0; 134 } 135 return elementCount; 136 } 137 138 139 /*************************************************************************** 140 */ 141 PaRingBufferSize PaUtil_AdvanceRingBufferWriteIndex( 142 PaUtilRingBuffer* rbuf, 143 PaRingBufferSize elementCount) { 144 /* we need to ensure that previous writes are seen before we update the write index */ 145 PaUtil_WriteMemoryBarrier(); 146 return rbuf->writeIndex = (rbuf->writeIndex + elementCount) & rbuf->bigMask; 147 } 148 149 /*************************************************************************** 150 ** Get address of region(s) from which we can read data. 151 ** If the region is contiguous, size2 will be zero. 152 ** If non-contiguous, size2 will be the size of second region. 153 ** Returns room available to be written or elementCount, whichever is smaller. 154 */ 155 PaRingBufferSize PaUtil_GetRingBufferReadRegions(PaUtilRingBuffer* rbuf, 156 PaRingBufferSize elementCount, 157 void** dataPtr1, 158 PaRingBufferSize* sizePtr1, 159 void** dataPtr2, 160 PaRingBufferSize* sizePtr2) { 161 PaRingBufferSize index; 162 PaRingBufferSize available = PaUtil_GetRingBufferReadAvailable( rbuf ); 163 if( elementCount > available ) elementCount = available; 164 /* Check to see if read is not contiguous. */ 165 index = rbuf->readIndex & rbuf->smallMask; 166 if( (index + elementCount) > rbuf->bufferSize ) 167 { 168 /* Write data in two blocks that wrap the buffer. */ 169 PaRingBufferSize firstHalf = rbuf->bufferSize - index; 170 *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; 171 *sizePtr1 = firstHalf; 172 *dataPtr2 = &rbuf->buffer[0]; 173 *sizePtr2 = elementCount - firstHalf; 174 } 175 else 176 { 177 *dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes]; 178 *sizePtr1 = elementCount; 179 *dataPtr2 = NULL; 180 *sizePtr2 = 0; 181 } 182 return elementCount; 183 } 184 /*************************************************************************** 185 */ 186 PaRingBufferSize PaUtil_AdvanceRingBufferReadIndex( 187 PaUtilRingBuffer* rbuf, 188 PaRingBufferSize elementCount) { 189 /* we need to ensure that previous writes are always seen before updating the index. */ 190 PaUtil_WriteMemoryBarrier(); 191 return rbuf->readIndex = (rbuf->readIndex + elementCount) & rbuf->bigMask; 192 } 193 194 /*************************************************************************** 195 ** Return elements written. */ 196 PaRingBufferSize PaUtil_WriteRingBuffer(PaUtilRingBuffer* rbuf, 197 const void* data, 198 PaRingBufferSize elementCount) { 199 PaRingBufferSize size1, size2, numWritten; 200 void *data1, *data2; 201 numWritten = PaUtil_GetRingBufferWriteRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 ); 202 if( size2 > 0 ) 203 { 204 205 memcpy( data1, data, size1*rbuf->elementSizeBytes ); 206 data = ((char *)data) + size1*rbuf->elementSizeBytes; 207 memcpy( data2, data, size2*rbuf->elementSizeBytes ); 208 } 209 else 210 { 211 memcpy( data1, data, size1*rbuf->elementSizeBytes ); 212 } 213 PaUtil_AdvanceRingBufferWriteIndex( rbuf, numWritten ); 214 return numWritten; 215 } 216 217 /*************************************************************************** 218 ** Return elements read. */ 219 PaRingBufferSize PaUtil_ReadRingBuffer(PaUtilRingBuffer* rbuf, 220 void* data, 221 PaRingBufferSize elementCount) { 222 PaRingBufferSize size1, size2, numRead; 223 void *data1, *data2; 224 numRead = PaUtil_GetRingBufferReadRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 ); 225 if( size2 > 0 ) 226 { 227 memcpy( data, data1, size1*rbuf->elementSizeBytes ); 228 data = ((char *)data) + size1*rbuf->elementSizeBytes; 229 memcpy( data, data2, size2*rbuf->elementSizeBytes ); 230 } 231 else 232 { 233 memcpy( data, data1, size1*rbuf->elementSizeBytes ); 234 } 235 PaUtil_AdvanceRingBufferReadIndex( rbuf, numRead ); 236 return numRead; 237 } 238