1 /* 2 * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ChunkCache.h" 8 9 #include <new> 10 #include <stdlib.h> 11 #include <string.h> 12 13 #include <Debug.h> 14 15 16 chunk_buffer::chunk_buffer() 17 : 18 buffer(NULL), 19 size(0), 20 capacity(0) 21 { 22 } 23 24 25 chunk_buffer::~chunk_buffer() 26 { 27 rtm_free(buffer); 28 } 29 30 31 // #pragma mark - 32 33 34 ChunkCache::ChunkCache(sem_id waitSem, size_t maxBytes) 35 : 36 BLocker("media chunk cache"), 37 fWaitSem(waitSem) 38 { 39 rtm_create_pool(&fRealTimePool, maxBytes, "media chunk cache"); 40 fMaxBytes = rtm_available(fRealTimePool); 41 } 42 43 44 ChunkCache::~ChunkCache() 45 { 46 rtm_delete_pool(fRealTimePool); 47 } 48 49 50 status_t 51 ChunkCache::InitCheck() const 52 { 53 if (fRealTimePool == NULL) 54 return B_NO_MEMORY; 55 56 return B_OK; 57 } 58 59 60 void 61 ChunkCache::MakeEmpty() 62 { 63 ASSERT(IsLocked()); 64 65 fUnusedChunks.MoveFrom(&fChunks); 66 67 release_sem(fWaitSem); 68 } 69 70 71 bool 72 ChunkCache::SpaceLeft() const 73 { 74 ASSERT(IsLocked()); 75 76 return sizeof(chunk_buffer) + 2048 < rtm_available(fRealTimePool); 77 } 78 79 80 chunk_buffer* 81 ChunkCache::NextChunk() 82 { 83 ASSERT(IsLocked()); 84 85 chunk_buffer* chunk = fChunks.RemoveHead(); 86 if (chunk != NULL) { 87 fInFlightChunks.Add(chunk); 88 release_sem(fWaitSem); 89 } 90 91 return chunk; 92 } 93 94 95 /*! Moves the specified chunk from the in-flight list to the unused list. 96 This means the chunk data can be overwritten again. 97 */ 98 void 99 ChunkCache::RecycleChunk(chunk_buffer* chunk) 100 { 101 ASSERT(IsLocked()); 102 103 fInFlightChunks.Remove(chunk); 104 fUnusedChunks.Add(chunk); 105 } 106 107 108 bool 109 ChunkCache::ReadNextChunk(Reader* reader, void* cookie) 110 { 111 ASSERT(IsLocked()); 112 113 // retrieve chunk buffer 114 chunk_buffer* chunk = fUnusedChunks.RemoveHead(); 115 if (chunk == NULL) { 116 // allocate a new one 117 chunk = (chunk_buffer*)rtm_alloc(fRealTimePool, sizeof(chunk_buffer)); 118 if (chunk == NULL) 119 return false; 120 121 new(chunk) chunk_buffer; 122 } 123 124 const void* buffer; 125 size_t bufferSize; 126 chunk->status = reader->GetNextChunk(cookie, &buffer, &bufferSize, 127 &chunk->header); 128 if (chunk->status == B_OK) { 129 if (chunk->capacity < bufferSize) { 130 // adapt buffer size 131 rtm_free(chunk->buffer); 132 chunk->capacity = (bufferSize + 2047) & ~2047; 133 chunk->buffer = rtm_alloc(fRealTimePool, chunk->capacity); 134 if (chunk->buffer == NULL) { 135 rtm_free(chunk); 136 return false; 137 } 138 } 139 140 memcpy(chunk->buffer, buffer, bufferSize); 141 chunk->size = bufferSize; 142 } 143 144 fChunks.Add(chunk); 145 return chunk->status == B_OK; 146 } 147