RingBuffer.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. * RingBuffer.cpp
  3. * simple_mp3_playback
  4. *
  5. * Created by Ben Allison on 11/10/07.
  6. * Copyright 2007 Nullsoft, Inc. All rights reserved.
  7. *
  8. */
  9. #include "RingBuffer.h"
  10. #include "../replicant/foundation/error.h"
  11. #include "bfc/platform/types.h"
  12. #include "bfc/platform/minmax.h"
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <algorithm>
  16. #ifdef MIN
  17. #undef MIN
  18. #endif // MIN
  19. #define MIN(a,b) ((a<b)?(a):(b))
  20. RingBuffer::~RingBuffer()
  21. {
  22. if ( ringBuffer )
  23. free( ringBuffer );
  24. ringBuffer = 0;
  25. }
  26. void RingBuffer::Reset()
  27. {
  28. if ( ringBuffer )
  29. free( ringBuffer );
  30. ringBuffer = 0;
  31. }
  32. bool RingBuffer::reserve( size_t bytes )
  33. {
  34. Reset();
  35. ringBufferSize = bytes;
  36. ringBuffer = (char *)calloc( ringBufferSize, sizeof( char ) );
  37. if ( !ringBuffer )
  38. return false;
  39. clear();
  40. return true;
  41. }
  42. int RingBuffer::expand( size_t bytes )
  43. {
  44. if ( bytes > ringBufferSize )
  45. {
  46. char *new_buffer = (char *)realloc( ringBuffer, bytes );
  47. if ( !new_buffer )
  48. return NErr_OutOfMemory;
  49. size_t write_offset = ringReadPosition - ringBuffer;
  50. size_t read_offset = ringWritePosition - ringBuffer;
  51. /* update write pointer for the new buffer */
  52. ringWritePosition = new_buffer + write_offset;
  53. if ( write_offset > read_offset || !ringBufferUsed ) /* ringBufferUsed will resolve the ambiguity when ringWritePosition == ringReadPosition */
  54. {
  55. /* the ring buffer looks like [ RXXXW ], so we don't need to move anything.
  56. Just update the read pointer */
  57. ringReadPosition = new_buffer + write_offset;
  58. }
  59. else
  60. {
  61. /* [XXW RXX] needs to become [XXW RXX] */
  62. size_t end_bytes = ringBufferSize - read_offset; // number of bytes that we need to relocate (the RXX portion)
  63. char *new_read_pointer = &new_buffer[ bytes - end_bytes ];
  64. memmove( new_read_pointer, ringReadPosition, end_bytes );
  65. ringReadPosition = new_read_pointer; /* update read pointer */
  66. }
  67. ringBufferSize = bytes;
  68. ringBuffer = new_buffer;
  69. return NErr_Success;
  70. }
  71. else
  72. return NErr_NoAction;
  73. }
  74. bool RingBuffer::empty() const
  75. {
  76. return ( ringBufferUsed == 0 );
  77. }
  78. size_t RingBuffer::read( void *dest, size_t len )
  79. {
  80. int8_t *out = (int8_t *)dest; // lets us do pointer math easier
  81. size_t toCopy = MIN( ringBufferUsed, len );
  82. size_t copied = 0;
  83. len -= toCopy;
  84. // read to the end of the ring buffer
  85. size_t end = ringBufferSize - ( ringReadPosition - ringBuffer );
  86. size_t read1 = MIN( end, toCopy );
  87. memcpy( out, ringReadPosition, read1 );
  88. copied += read1;
  89. ringReadPosition += read1;
  90. if ( ringReadPosition == ringBuffer + ringBufferSize )
  91. ringReadPosition = ringBuffer;
  92. // update positions
  93. ringBufferUsed -= read1;
  94. toCopy -= read1;
  95. out = (int8_t *)out + read1;
  96. // see if we still have more to read after wrapping around
  97. if ( toCopy )
  98. {
  99. memcpy( out, ringReadPosition, toCopy );
  100. copied += toCopy;
  101. ringReadPosition += toCopy;
  102. ringBufferUsed -= toCopy;
  103. if ( ringReadPosition == ringBuffer + ringBufferSize )
  104. ringReadPosition = ringBuffer;
  105. }
  106. return copied;
  107. }
  108. size_t RingBuffer::at(size_t offset, void *dest, size_t len) const
  109. {
  110. size_t toCopy = ringBufferUsed;
  111. // make a local copy of this so we don't blow the original
  112. char *ringReadPosition = this->ringReadPosition;
  113. /* --- do a "dummy read" to deal with the offset request --- */
  114. size_t dummy_end = ringBufferSize-(ringReadPosition-ringBuffer);
  115. offset = MIN(toCopy, offset);
  116. size_t read0 = MIN(dummy_end, offset);
  117. ringReadPosition+=read0;
  118. if (ringReadPosition == ringBuffer + ringBufferSize)
  119. ringReadPosition = ringBuffer;
  120. // update positions
  121. toCopy -= read0;
  122. offset -= read0;
  123. // do second-half read (wraparound)
  124. if ( offset )
  125. {
  126. ringReadPosition += offset;
  127. toCopy -= offset;
  128. }
  129. // dummy read done
  130. /* --- set up destination buffer and copy size --- */
  131. int8_t *out = (int8_t *)dest; // lets us do pointer math easier
  132. if ( toCopy > len )
  133. toCopy = len;
  134. size_t copied=0;
  135. /* --- read to the end of the ring buffer --- */
  136. size_t end = ringBufferSize - ( ringReadPosition - ringBuffer );
  137. size_t read1 = MIN( end, toCopy );
  138. memcpy( out, ringReadPosition, read1 );
  139. copied += read1;
  140. ringReadPosition += read1;
  141. if (ringReadPosition == ringBuffer + ringBufferSize)
  142. ringReadPosition = ringBuffer;
  143. // update positions
  144. toCopy -= read1;
  145. out = (int8_t *)out + read1;
  146. /* --- see if we still have more to read after wrapping around --- */
  147. if (toCopy)
  148. {
  149. memcpy(out, ringReadPosition, toCopy);
  150. copied += toCopy;
  151. ringReadPosition += toCopy;
  152. }
  153. return copied;
  154. }
  155. size_t RingBuffer::peek( void *dest, size_t len ) const
  156. {
  157. int8_t *out = (int8_t *)dest; // lets us do pointer math easier
  158. size_t toCopy = MIN( ringBufferUsed, len );
  159. size_t copied = 0;
  160. // make a local copy of this so we don't blow the original
  161. char *ringReadPosition = this->ringReadPosition;
  162. // read to the end of the ring buffer
  163. size_t end = ringBufferSize - ( ringReadPosition - ringBuffer );
  164. size_t read1 = MIN( end, toCopy );
  165. memcpy( out, ringReadPosition, read1 );
  166. copied += read1;
  167. ringReadPosition += read1;
  168. if ( ringReadPosition == ringBuffer + ringBufferSize )
  169. ringReadPosition = ringBuffer;
  170. // update positions
  171. toCopy -= read1;
  172. out = (int8_t *)out + read1;
  173. // see if we still have more to read after wrapping around
  174. if ( toCopy )
  175. {
  176. memcpy( out, ringReadPosition, toCopy );
  177. copied += toCopy;
  178. ringReadPosition += toCopy;
  179. }
  180. return copied;
  181. }
  182. size_t RingBuffer::advance( size_t len )
  183. {
  184. size_t toCopy = MIN( ringBufferUsed, len );
  185. size_t copied = 0;
  186. len -= toCopy;
  187. // read to the end of the ring buffer
  188. size_t end = ringBufferSize - ( ringReadPosition - ringBuffer );
  189. size_t read1 = MIN( end, toCopy );
  190. copied += read1;
  191. ringReadPosition += read1;
  192. if ( ringReadPosition == ringBuffer + ringBufferSize )
  193. ringReadPosition = ringBuffer;
  194. // update positions
  195. toCopy -= read1;
  196. ringBufferUsed -= read1;
  197. // see if we still have more to read after wrapping around
  198. if ( toCopy )
  199. {
  200. copied += toCopy;
  201. ringReadPosition += toCopy;
  202. ringBufferUsed -= toCopy;
  203. if ( ringReadPosition == ringBuffer + ringBufferSize )
  204. ringReadPosition = ringBuffer;
  205. }
  206. return copied;
  207. }
  208. size_t RingBuffer::avail() const
  209. {
  210. return ringBufferSize - ringBufferUsed;
  211. }
  212. size_t RingBuffer::write( const void *buffer, size_t bytes )
  213. {
  214. size_t used = ringBufferUsed;
  215. size_t avail = ringBufferSize - used;
  216. bytes = MIN( avail, bytes );
  217. // write to the end of the ring buffer
  218. size_t end = ringBufferSize - ( ringWritePosition - ringBuffer );
  219. size_t copied = 0;
  220. size_t write1 = MIN( end, bytes );
  221. memcpy( ringWritePosition, buffer, write1 );
  222. copied += write1;
  223. ringWritePosition += write1;
  224. if ( ringWritePosition == ringBuffer + ringBufferSize )
  225. ringWritePosition = ringBuffer;
  226. // update positions
  227. ringBufferUsed += write1;
  228. bytes -= write1;
  229. buffer = (const int8_t *)buffer + write1;
  230. // see if we still have more to write after wrapping around
  231. if ( bytes )
  232. {
  233. memcpy( ringWritePosition, buffer, bytes );
  234. copied += bytes;
  235. ringWritePosition += bytes;
  236. ringBufferUsed += bytes;
  237. if ( ringWritePosition == ringBuffer + ringBufferSize )
  238. ringWritePosition = ringBuffer;
  239. }
  240. return copied;
  241. }
  242. size_t RingBuffer::drain( Drainer *drainer, size_t max_bytes )
  243. {
  244. // read to the end of the ring buffer
  245. size_t used = ringBufferUsed;
  246. size_t bytes = used;
  247. bytes = MIN(bytes, max_bytes);
  248. size_t copied = 0;
  249. size_t end = ringBufferSize-(ringReadPosition-ringBuffer);
  250. size_t drain1 = MIN(end, bytes);
  251. if (!drain1)
  252. return 0;
  253. size_t read1 = drainer->Write(ringReadPosition, drain1);
  254. if (read1 == 0)
  255. return 0;
  256. copied+=read1;
  257. ringReadPosition+=read1;
  258. if (ringReadPosition == ringBuffer + ringBufferSize)
  259. ringReadPosition=ringBuffer;
  260. // update positions
  261. ringBufferUsed -= read1;
  262. bytes-=read1;
  263. // see if we still have more to read after wrapping around
  264. if (drain1 == read1 && bytes)
  265. {
  266. size_t read2 = drainer->Write(ringReadPosition, bytes);
  267. copied += read2;
  268. ringReadPosition += read2;
  269. ringBufferUsed -= read2;
  270. if (ringReadPosition == ringBuffer + ringBufferSize)
  271. ringReadPosition=ringBuffer;
  272. }
  273. return copied;
  274. }
  275. size_t RingBuffer::fill(Filler *filler, size_t max_bytes)
  276. {
  277. // write to the end of the ring buffer
  278. size_t used = ringBufferUsed;
  279. size_t bytes = ringBufferSize - used;
  280. bytes = MIN(bytes, max_bytes);
  281. size_t copied = 0;
  282. size_t end = ringBufferSize-(ringWritePosition-ringBuffer);
  283. size_t fill1 = MIN(end, bytes);
  284. if (!fill1)
  285. return 0;
  286. size_t write1 = filler->Read(ringWritePosition, fill1);
  287. if (write1 == 0)
  288. return 0;
  289. copied+=write1;
  290. ringWritePosition+=write1;
  291. if (ringWritePosition == ringBuffer + ringBufferSize)
  292. ringWritePosition=ringBuffer;
  293. // update positions
  294. ringBufferUsed += write1;
  295. bytes-=write1;
  296. // see if we still have more to write after wrapping around
  297. if (fill1 == write1 && bytes)
  298. {
  299. size_t write2 = filler->Read(ringWritePosition, bytes);
  300. copied += write2;
  301. ringWritePosition += write2;
  302. ringBufferUsed += write2;
  303. if (ringWritePosition == ringBuffer + ringBufferSize)
  304. ringWritePosition=ringBuffer;
  305. }
  306. return copied;
  307. }
  308. size_t RingBuffer::size() const
  309. {
  310. return ringBufferUsed;
  311. }
  312. void RingBuffer::clear()
  313. {
  314. ringBufferUsed = 0;
  315. ringWritePosition = ringBuffer;
  316. ringReadPosition = ringBuffer;
  317. }
  318. void *RingBuffer::LockBuffer()
  319. {
  320. return ringBuffer;
  321. }
  322. void RingBuffer::UnlockBuffer( size_t written )
  323. {
  324. ringWritePosition = ringBuffer+written;
  325. ringBufferUsed = written;
  326. }
  327. size_t RingBuffer::write_position() const
  328. {
  329. return (size_t)ringWritePosition;
  330. }
  331. size_t RingBuffer::read_position() const
  332. {
  333. return (size_t)ringReadPosition;
  334. }
  335. void RingBuffer::get_read_buffer(size_t bytes, const void **buffer, size_t *bytes_available) const
  336. {
  337. size_t toCopy = MIN( ringBufferUsed, bytes );
  338. // read to the end of the ring buffer
  339. size_t end = ringBufferSize-(ringReadPosition-ringBuffer);
  340. *bytes_available = MIN(end, toCopy);
  341. *buffer = ringReadPosition;
  342. }