/* * Copyright 2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #include "ChunkCache.h" #include #include #include #include "MediaDebug.h" // #pragma mark - ChunkCache::ChunkCache(sem_id waitSem, size_t maxBytes) : BLocker("media chunk cache"), fWaitSem(waitSem) { rtm_create_pool(&fRealTimePool, maxBytes, "media chunk cache"); fMaxBytes = rtm_available(fRealTimePool); } ChunkCache::~ChunkCache() { rtm_delete_pool(fRealTimePool); } status_t ChunkCache::InitCheck() const { if (fRealTimePool == NULL) return B_NO_MEMORY; return B_OK; } void ChunkCache::MakeEmpty() { ASSERT(IsLocked()); while (!fChunkCache.empty()) { RecycleChunk(fChunkCache.front()); fChunkCache.pop(); } release_sem(fWaitSem); } bool ChunkCache::SpaceLeft() const { ASSERT(IsLocked()); if (fChunkCache.size() >= CACHE_MAX_ENTRIES) { return false; } // If there is no more memory we are likely to fail soon after return sizeof(chunk_buffer) + 2048 < rtm_available(fRealTimePool); } chunk_buffer* ChunkCache::NextChunk(Reader* reader, void* cookie) { ASSERT(IsLocked()); chunk_buffer* chunk = NULL; if (fChunkCache.empty()) { TRACE("ChunkCache is empty, going direct to reader\n"); if (ReadNextChunk(reader, cookie)) { return NextChunk(reader, cookie); } } else { chunk = fChunkCache.front(); fChunkCache.pop(); release_sem(fWaitSem); } return chunk; } /* Moves the specified chunk to the unused list. This means the chunk data can be overwritten again. */ void ChunkCache::RecycleChunk(chunk_buffer* chunk) { ASSERT(IsLocked()); rtm_free(chunk->buffer); chunk->capacity = 0; chunk->size = 0; chunk->buffer = NULL; fUnusedChunks.push_back(chunk); } bool ChunkCache::ReadNextChunk(Reader* reader, void* cookie) { ASSERT(IsLocked()); // retrieve chunk buffer chunk_buffer* chunk = NULL; if (fUnusedChunks.empty()) { // allocate a new one chunk = (chunk_buffer*)rtm_alloc(fRealTimePool, sizeof(chunk_buffer)); if (chunk == NULL) { ERROR("RTM Pool empty allocating chunk buffer structure"); return false; } chunk->size = 0; chunk->capacity = 0; chunk->buffer = NULL; } else { chunk = fUnusedChunks.front(); fUnusedChunks.pop_front(); } const void* buffer; size_t bufferSize; chunk->status = reader->GetNextChunk(cookie, &buffer, &bufferSize, &chunk->header); if (chunk->status == B_OK) { if (chunk->capacity < bufferSize) { // adapt buffer size rtm_free(chunk->buffer); chunk->capacity = (bufferSize + 2047) & ~2047; chunk->buffer = rtm_alloc(fRealTimePool, chunk->capacity); if (chunk->buffer == NULL) { rtm_free(chunk); ERROR("RTM Pool empty allocating chunk buffer\n"); return false; } } memcpy(chunk->buffer, buffer, bufferSize); chunk->size = bufferSize; } fChunkCache.push(chunk); return chunk->status == B_OK; }