xref: /haiku/src/kits/media/ChunkCache.cpp (revision fa66a805cce4fd4e4fc501ed6e22c0ed684fab9a)
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