1/*
2 * Copyright 2019, Ryan Leavengood.
3 * Copyright 2009, Axel D��rfler, axeld@pinc-software.de.
4 * Copyright 2002, Marcus Overhagen. All Rights Reserved.
5 * Distributed under the terms of the MIT License.
6 */
7
8
9//! A cache for BBuffers to be received by BBufferConsumer::BufferReceived().
10
11
12#include "BufferCache.h"
13
14#include <Buffer.h>
15
16#include "MediaDebug.h"
17#include "MediaMisc.h"
18#include "SharedBufferList.h"
19
20
21namespace BPrivate {
22
23
24BufferCache::BufferCache()
25{
26}
27
28
29BufferCache::~BufferCache()
30{
31	BufferMap::Iterator iterator = fMap.GetIterator();
32	while (iterator.HasNext()) {
33		BufferMap::Entry entry = iterator.Next();
34		delete entry.value.buffer;
35	}
36}
37
38
39BBuffer*
40BufferCache::GetBuffer(media_buffer_id id, port_id port)
41{
42	if (id <= 0)
43		return NULL;
44
45	buffer_cache_entry* existing;
46	if (fMap.Get(id, existing)) {
47		existing->buffer->fFlags |= BUFFER_TO_RECLAIM;
48		return existing->buffer;
49	}
50
51	buffer_clone_info info;
52	info.buffer = id;
53	BBuffer* buffer = new(std::nothrow) BBuffer(info);
54	if (buffer == NULL || buffer->ID() <= 0
55			|| buffer->Data() == NULL) {
56		delete buffer;
57		return NULL;
58	}
59
60	if (buffer->ID() != id)
61		debugger("BufferCache::GetBuffer: IDs mismatch");
62
63	buffer_cache_entry entry;
64	entry.buffer = buffer;
65	entry.port = port;
66	status_t error = fMap.Put(id, entry);
67	if (error != B_OK) {
68		delete buffer;
69		return NULL;
70	}
71
72	buffer->fFlags |= BUFFER_TO_RECLAIM;
73	return buffer;
74}
75
76
77void
78BufferCache::FlushCacheForPort(port_id port)
79{
80	BufferMap::Iterator iterator = fMap.GetIterator();
81	while (iterator.HasNext()) {
82		BufferMap::Entry entry = iterator.Next();
83		if (entry.value.port == port) {
84			BBuffer* buffer = entry.value.buffer;
85			bool isReclaimed = (buffer->fFlags & BUFFER_TO_RECLAIM) == 0;
86			if (isReclaimed && buffer->fBufferList != NULL)
87				isReclaimed = buffer->fBufferList->RemoveBuffer(buffer) == B_OK;
88
89			if (isReclaimed)
90				delete buffer;
91			else {
92				// mark the buffer for deletion
93				buffer->fFlags |= BUFFER_MARKED_FOR_DELETION;
94			}
95			// Then remove it from the map
96			fMap.Remove(iterator);
97		}
98	}
99}
100
101
102}	// namespace BPrivate
103