1255a01c7Sbeveloper/*
2255a01c7Sbeveloper * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
3255a01c7Sbeveloper *
4255a01c7Sbeveloper * Permission is hereby granted, free of charge, to any person obtaining
5255a01c7Sbeveloper * a copy of this software and associated documentation files or portions
6255a01c7Sbeveloper * thereof (the "Software"), to deal in the Software without restriction,
7255a01c7Sbeveloper * including without limitation the rights to use, copy, modify, merge,
8255a01c7Sbeveloper * publish, distribute, sublicense, and/or sell copies of the Software,
9255a01c7Sbeveloper * and to permit persons to whom the Software is furnished to do so, subject
10255a01c7Sbeveloper * to the following conditions:
11255a01c7Sbeveloper *
12255a01c7Sbeveloper *  * Redistributions of source code must retain the above copyright notice,
13255a01c7Sbeveloper *    this list of conditions and the following disclaimer.
14255a01c7Sbeveloper *
15255a01c7Sbeveloper *  * Redistributions in binary form must reproduce the above copyright notice
16255a01c7Sbeveloper *    in the  binary, as well as this list of conditions and the following
17255a01c7Sbeveloper *    disclaimer in the documentation and/or other materials provided with
18255a01c7Sbeveloper *    the distribution.
19255a01c7Sbeveloper *
20255a01c7Sbeveloper * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21255a01c7Sbeveloper * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22255a01c7Sbeveloper * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23255a01c7Sbeveloper * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24255a01c7Sbeveloper * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25255a01c7Sbeveloper * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26255a01c7Sbeveloper * THE SOFTWARE.
27255a01c7Sbeveloper *
28255a01c7Sbeveloper */
2952a38012Sejakowatz
30255a01c7Sbeveloper/* Implements _event_queue_imp used by BTimedEventQueue, not thread save!
31255a01c7Sbeveloper */
32ba5e652dSAdrien Destugues#include <string.h>
33ba5e652dSAdrien Destugues
3452a38012Sejakowatz#include <Autolock.h>
3552a38012Sejakowatz#include <Buffer.h>
3652a38012Sejakowatz#include <InterfaceDefs.h> //defines B_DELETE
37ba5e652dSAdrien Destugues#include <TimedEventQueue.h>
38ba5e652dSAdrien Destugues#include <TimeSource.h>
39ba5e652dSAdrien Destugues
4052a38012Sejakowatz#include "TimedEventQueuePrivate.h"
41ba5e652dSAdrien Destugues
4252a38012Sejakowatz#include "Debug.h"
43b84955d4SBarrett#include "MediaDebug.h"
4452a38012Sejakowatz
4552a38012Sejakowatz_event_queue_imp::_event_queue_imp() :
4641ba915dSbeveloper	fLock(new BLocker("BTimedEventQueue locker")),
4752a38012Sejakowatz	fEventCount(0),
4852a38012Sejakowatz	fFirstEntry(NULL),
4952a38012Sejakowatz	fLastEntry(NULL),
5052a38012Sejakowatz	fCleanupHookContext(NULL),
5152a38012Sejakowatz	fCleanupHook(0)
5252a38012Sejakowatz{
5352a38012Sejakowatz}
5452a38012Sejakowatz
5552a38012Sejakowatz
5652a38012Sejakowatz_event_queue_imp::~_event_queue_imp()
5752a38012Sejakowatz{
5852a38012Sejakowatz	event_queue_entry *entry;
5952a38012Sejakowatz	entry = fFirstEntry;
6052a38012Sejakowatz	while (entry) {
6152a38012Sejakowatz		event_queue_entry *deleteme;
6252a38012Sejakowatz		deleteme = entry;
6352a38012Sejakowatz		entry = entry->next;
6452a38012Sejakowatz		delete deleteme;
6552a38012Sejakowatz	}
6641ba915dSbeveloper	delete fLock;
6752a38012Sejakowatz}
6852a38012Sejakowatz
69332cc6bcSAxel Dörfler
7052a38012Sejakowatzstatus_t
7152a38012Sejakowatz_event_queue_imp::AddEvent(const media_timed_event &event)
7252a38012Sejakowatz{
7352a38012Sejakowatz	BAutolock lock(fLock);
745917dd5bSbeveloper
755917dd5bSbeveloper//	printf("        adding      %12Ld  at %12Ld\n", event.event_time, system_time());
76332cc6bcSAxel Dörfler
7752a38012Sejakowatz	if (event.type <= 0) {
7852a38012Sejakowatz		 return B_BAD_VALUE;
7952a38012Sejakowatz	}
80332cc6bcSAxel Dörfler
8152a38012Sejakowatz	//create a new queue
8252a38012Sejakowatz	if (fFirstEntry == NULL) {
8352a38012Sejakowatz		ASSERT(fEventCount == 0);
8452a38012Sejakowatz		ASSERT(fLastEntry == NULL);
8552a38012Sejakowatz		fFirstEntry = fLastEntry = new event_queue_entry;
8649811b3aSMarcus Overhagen		fFirstEntry->event = event;
8752a38012Sejakowatz		fFirstEntry->prev = NULL;
8852a38012Sejakowatz		fFirstEntry->next = NULL;
8952a38012Sejakowatz		fEventCount++;
9052a38012Sejakowatz		return B_OK;
9152a38012Sejakowatz	}
92332cc6bcSAxel Dörfler
9352a38012Sejakowatz	//insert at queue begin
9452a38012Sejakowatz	if (fFirstEntry->event.event_time >= event.event_time) {
9552a38012Sejakowatz		event_queue_entry *newentry = new event_queue_entry;
9649811b3aSMarcus Overhagen		newentry->event = event;
9752a38012Sejakowatz		newentry->prev = NULL;
9852a38012Sejakowatz		newentry->next = fFirstEntry;
9952a38012Sejakowatz		fFirstEntry->prev = newentry;
10052a38012Sejakowatz		fFirstEntry = newentry;
10152a38012Sejakowatz		fEventCount++;
10252a38012Sejakowatz		return B_OK;
10352a38012Sejakowatz	}
10452a38012Sejakowatz
10552a38012Sejakowatz	//insert at queue end
10652a38012Sejakowatz	if (fLastEntry->event.event_time <= event.event_time) {
10752a38012Sejakowatz		event_queue_entry *newentry = new event_queue_entry;
10849811b3aSMarcus Overhagen		newentry->event = event;
10952a38012Sejakowatz		newentry->prev = fLastEntry;
11052a38012Sejakowatz		newentry->next = NULL;
11152a38012Sejakowatz		fLastEntry->next = newentry;
11252a38012Sejakowatz		fLastEntry = newentry;
11352a38012Sejakowatz		fEventCount++;
11452a38012Sejakowatz		return B_OK;
11552a38012Sejakowatz	}
116332cc6bcSAxel Dörfler
11752a38012Sejakowatz	//insert into the queue
11852a38012Sejakowatz	for (event_queue_entry *entry = fLastEntry; entry; entry = entry->prev) {
11952a38012Sejakowatz		if (entry->event.event_time <= event.event_time) {
12052a38012Sejakowatz			//insert after entry
12152a38012Sejakowatz			event_queue_entry *newentry = new event_queue_entry;
12249811b3aSMarcus Overhagen			newentry->event = event;
12352a38012Sejakowatz			newentry->prev = entry;
12452a38012Sejakowatz			newentry->next = entry->next;
12552a38012Sejakowatz			(entry->next)->prev = newentry;
12652a38012Sejakowatz			entry->next = newentry;
12752a38012Sejakowatz			fEventCount++;
12852a38012Sejakowatz			return B_OK;
12952a38012Sejakowatz		}
13052a38012Sejakowatz	}
131332cc6bcSAxel Dörfler
13252a38012Sejakowatz	debugger("_event_queue_imp::AddEvent failed, should not be here\n");
13352a38012Sejakowatz	return B_OK;
13452a38012Sejakowatz}
13552a38012Sejakowatz
13652a38012Sejakowatz
13752a38012Sejakowatzstatus_t
13852a38012Sejakowatz_event_queue_imp::RemoveEvent(const media_timed_event *event)
13952a38012Sejakowatz{
14052a38012Sejakowatz	BAutolock lock(fLock);
14152a38012Sejakowatz
14252a38012Sejakowatz	for (event_queue_entry *entry = fFirstEntry; entry; entry = entry->next) {
14352a38012Sejakowatz		if (entry->event == *event) {
14452a38012Sejakowatz			// No cleanup here
14552a38012Sejakowatz			RemoveEntry(entry);
14652a38012Sejakowatz			return B_OK;
14752a38012Sejakowatz		}
14852a38012Sejakowatz	}
14952a38012Sejakowatz
15052a38012Sejakowatz	return B_ERROR;
15152a38012Sejakowatz}
15252a38012Sejakowatz
15352a38012Sejakowatz
15452a38012Sejakowatzstatus_t
15552a38012Sejakowatz_event_queue_imp::RemoveFirstEvent(media_timed_event * outEvent)
15652a38012Sejakowatz{
15752a38012Sejakowatz	BAutolock lock(fLock);
158332cc6bcSAxel Dörfler
15952a38012Sejakowatz	if (fFirstEntry == 0)
16052a38012Sejakowatz		return B_ERROR;
161332cc6bcSAxel Dörfler
1629bedd42cSbeveloper	if (outEvent != 0) {
1639bedd42cSbeveloper		// No cleanup here
16452a38012Sejakowatz		*outEvent = fFirstEntry->event;
1659bedd42cSbeveloper	} else {
16652a38012Sejakowatz		CleanupEvent(&fFirstEntry->event);
1679bedd42cSbeveloper	}
1689bedd42cSbeveloper
16952a38012Sejakowatz	RemoveEntry(fFirstEntry);
17052a38012Sejakowatz
17152a38012Sejakowatz	return B_OK;
17252a38012Sejakowatz}
17352a38012Sejakowatz
174332cc6bcSAxel Dörfler
17552a38012Sejakowatzbool
17652a38012Sejakowatz_event_queue_imp::HasEvents() const
17752a38012Sejakowatz{
17852a38012Sejakowatz	return fEventCount != 0;
17952a38012Sejakowatz}
18052a38012Sejakowatz
18152a38012Sejakowatz
18252a38012Sejakowatzint32
18352a38012Sejakowatz_event_queue_imp::EventCount() const
18452a38012Sejakowatz{
18552a38012Sejakowatz	#if DEBUG > 1
18652a38012Sejakowatz		Dump();
18752a38012Sejakowatz	#endif
18852a38012Sejakowatz	return fEventCount;
18952a38012Sejakowatz}
19052a38012Sejakowatz
19152a38012Sejakowatz
192332cc6bcSAxel Dörflerconst media_timed_event *
19352a38012Sejakowatz_event_queue_imp::FirstEvent() const
194332cc6bcSAxel Dörfler{
195332cc6bcSAxel Dörfler	return fFirstEntry ? &fFirstEntry->event : NULL;
19652a38012Sejakowatz}
197332cc6bcSAxel Dörfler
19852a38012Sejakowatz
19952a38012Sejakowatzbigtime_t
20052a38012Sejakowatz_event_queue_imp::FirstEventTime() const
201332cc6bcSAxel Dörfler{
202332cc6bcSAxel Dörfler	return fFirstEntry ? fFirstEntry->event.event_time : B_INFINITE_TIMEOUT;
20352a38012Sejakowatz}
20452a38012Sejakowatz
20552a38012Sejakowatz
206332cc6bcSAxel Dörflerconst media_timed_event *
20752a38012Sejakowatz_event_queue_imp::LastEvent() const
208332cc6bcSAxel Dörfler{
209332cc6bcSAxel Dörfler	return fLastEntry ? &fLastEntry->event : NULL;
21052a38012Sejakowatz}
21152a38012Sejakowatz
21252a38012Sejakowatz
213332cc6bcSAxel Dörflerbigtime_t
21452a38012Sejakowatz_event_queue_imp::LastEventTime() const
21552a38012Sejakowatz{
216332cc6bcSAxel Dörfler	return fLastEntry ? fLastEntry->event.event_time : B_INFINITE_TIMEOUT;
21752a38012Sejakowatz}
21852a38012Sejakowatz
21952a38012Sejakowatz
22052a38012Sejakowatzconst media_timed_event *
22152a38012Sejakowatz_event_queue_imp::FindFirstMatch(bigtime_t eventTime,
22252a38012Sejakowatz								 BTimedEventQueue::time_direction direction,
22352a38012Sejakowatz								 bool inclusive,
22452a38012Sejakowatz								 int32 eventType)
22552a38012Sejakowatz{
22652a38012Sejakowatz	event_queue_entry *end;
22752a38012Sejakowatz	event_queue_entry *entry;
22852a38012Sejakowatz
22952a38012Sejakowatz	BAutolock lock(fLock);
23052a38012Sejakowatz
23152a38012Sejakowatz	switch (direction) {
23252a38012Sejakowatz		case BTimedEventQueue::B_ALWAYS:
23352a38012Sejakowatz			for (entry = fFirstEntry; entry; entry = entry->next) {
23452a38012Sejakowatz				if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type)
23552a38012Sejakowatz					return &entry->event;
23652a38012Sejakowatz			}
23752a38012Sejakowatz			return NULL;
23852a38012Sejakowatz
23952a38012Sejakowatz		case BTimedEventQueue::B_BEFORE_TIME:
24052a38012Sejakowatz			end = GetEnd_BeforeTime(eventTime, inclusive);
24152a38012Sejakowatz			if (end == NULL)
24252a38012Sejakowatz				return NULL;
24352a38012Sejakowatz			end = end->next;
24452a38012Sejakowatz			for (entry = fFirstEntry; entry != end; entry = entry->next) {
24552a38012Sejakowatz				if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
24652a38012Sejakowatz					return &entry->event;
24752a38012Sejakowatz				}
24852a38012Sejakowatz			}
24952a38012Sejakowatz			return NULL;
25052a38012Sejakowatz
25152a38012Sejakowatz		case BTimedEventQueue::B_AT_TIME:
25252a38012Sejakowatz			{
25352a38012Sejakowatz				bool found_time = false;
25452a38012Sejakowatz				for (entry = fFirstEntry; entry; entry = entry->next) {
25552a38012Sejakowatz					if (eventTime == entry->event.event_time) {
25652a38012Sejakowatz						found_time = true;
25752a38012Sejakowatz						if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type)
25852a38012Sejakowatz							return &entry->event;
25952a38012Sejakowatz					} else if (found_time)
26052a38012Sejakowatz						return NULL;
26152a38012Sejakowatz				}
26252a38012Sejakowatz				return NULL;
26352a38012Sejakowatz			}
26452a38012Sejakowatz
26552a38012Sejakowatz		case BTimedEventQueue::B_AFTER_TIME:
26652a38012Sejakowatz			for (entry = GetStart_AfterTime(eventTime, inclusive); entry; entry = entry->next) {
26752a38012Sejakowatz				if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
26852a38012Sejakowatz					return &entry->event;
26952a38012Sejakowatz				}
27052a38012Sejakowatz			}
27152a38012Sejakowatz			return NULL;
27252a38012Sejakowatz	}
27352a38012Sejakowatz
27452a38012Sejakowatz	return NULL;
27552a38012Sejakowatz}
27652a38012Sejakowatz
27752a38012Sejakowatz
27852a38012Sejakowatzstatus_t
27952a38012Sejakowatz_event_queue_imp::DoForEach(BTimedEventQueue::for_each_hook hook,
28052a38012Sejakowatz							void *context,
28152a38012Sejakowatz							bigtime_t eventTime,
28252a38012Sejakowatz							BTimedEventQueue::time_direction direction,
28352a38012Sejakowatz							bool inclusive,
28452a38012Sejakowatz							int32 eventType)
28552a38012Sejakowatz{
28652a38012Sejakowatz	event_queue_entry *end;
28752a38012Sejakowatz	event_queue_entry *entry;
28852a38012Sejakowatz	event_queue_entry *remove;
28952a38012Sejakowatz	BTimedEventQueue::queue_action action;
29052a38012Sejakowatz
29152a38012Sejakowatz	BAutolock lock(fLock);
29252a38012Sejakowatz
29352a38012Sejakowatz	switch (direction) {
29452a38012Sejakowatz		case BTimedEventQueue::B_ALWAYS:
29552a38012Sejakowatz			for (entry = fFirstEntry; entry; ) {
29652a38012Sejakowatz				if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
29752a38012Sejakowatz					action = (*hook)(&entry->event, context);
29852a38012Sejakowatz					switch (action) {
299332cc6bcSAxel Dörfler						case BTimedEventQueue::B_DONE:
30052a38012Sejakowatz							return B_OK;
30152a38012Sejakowatz						case BTimedEventQueue::B_REMOVE_EVENT:
30252a38012Sejakowatz							CleanupEvent(&entry->event);
30352a38012Sejakowatz							remove = entry;
30452a38012Sejakowatz							entry = entry->next;
30552a38012Sejakowatz							RemoveEntry(remove);
30652a38012Sejakowatz							break;
30752a38012Sejakowatz						case BTimedEventQueue::B_NO_ACTION:
30852a38012Sejakowatz						case BTimedEventQueue::B_RESORT_QUEUE:
30952a38012Sejakowatz						default:
31052a38012Sejakowatz							entry = entry->next;
31152a38012Sejakowatz							break;
31252a38012Sejakowatz					}
31352a38012Sejakowatz				} else {
31452a38012Sejakowatz					entry = entry->next;
31552a38012Sejakowatz				}
31652a38012Sejakowatz			}
31752a38012Sejakowatz			return B_OK;
31852a38012Sejakowatz
31952a38012Sejakowatz		case BTimedEventQueue::B_BEFORE_TIME:
32052a38012Sejakowatz			end = GetEnd_BeforeTime(eventTime, inclusive);
32152a38012Sejakowatz			if (end == NULL)
32252a38012Sejakowatz				return B_OK;
32352a38012Sejakowatz			end = end->next;
32452a38012Sejakowatz			for (entry = fFirstEntry; entry != end; ) {
32552a38012Sejakowatz				if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
32652a38012Sejakowatz					action = (*hook)(&entry->event, context);
32752a38012Sejakowatz					switch (action) {
328332cc6bcSAxel Dörfler						case BTimedEventQueue::B_DONE:
32952a38012Sejakowatz							return B_OK;
33052a38012Sejakowatz						case BTimedEventQueue::B_REMOVE_EVENT:
33152a38012Sejakowatz							CleanupEvent(&entry->event);
33252a38012Sejakowatz							remove = entry;
33352a38012Sejakowatz							entry = entry->next;
33452a38012Sejakowatz							RemoveEntry(remove);
33552a38012Sejakowatz							break;
33652a38012Sejakowatz						case BTimedEventQueue::B_NO_ACTION:
33752a38012Sejakowatz						case BTimedEventQueue::B_RESORT_QUEUE:
33852a38012Sejakowatz						default:
33952a38012Sejakowatz							entry = entry->next;
34052a38012Sejakowatz							break;
34152a38012Sejakowatz					}
34252a38012Sejakowatz				} else {
34352a38012Sejakowatz					entry = entry->next;
34452a38012Sejakowatz				}
34552a38012Sejakowatz			}
34652a38012Sejakowatz			return B_OK;
34752a38012Sejakowatz
34852a38012Sejakowatz		case BTimedEventQueue::B_AT_TIME:
34952a38012Sejakowatz			{
35052a38012Sejakowatz				bool found_time = false;
35152a38012Sejakowatz				for (entry = fFirstEntry; entry; ) {
35252a38012Sejakowatz					if (eventTime == entry->event.event_time) {
35352a38012Sejakowatz						found_time = true;
35452a38012Sejakowatz						if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
35552a38012Sejakowatz							action = (*hook)(&entry->event, context);
35652a38012Sejakowatz							switch (action) {
357332cc6bcSAxel Dörfler								case BTimedEventQueue::B_DONE:
35852a38012Sejakowatz									return B_OK;
35952a38012Sejakowatz								case BTimedEventQueue::B_REMOVE_EVENT:
36052a38012Sejakowatz									CleanupEvent(&entry->event);
36152a38012Sejakowatz									remove = entry;
36252a38012Sejakowatz									entry = entry->next;
36352a38012Sejakowatz									RemoveEntry(remove);
36452a38012Sejakowatz									break;
36552a38012Sejakowatz								case BTimedEventQueue::B_NO_ACTION:
36652a38012Sejakowatz								case BTimedEventQueue::B_RESORT_QUEUE:
36752a38012Sejakowatz								default:
36852a38012Sejakowatz									entry = entry->next;
36952a38012Sejakowatz									break;
37052a38012Sejakowatz							}
37152a38012Sejakowatz						} else {
37252a38012Sejakowatz							entry = entry->next;
37352a38012Sejakowatz						}
37452a38012Sejakowatz					} else if (found_time) {
37552a38012Sejakowatz						break;
37652a38012Sejakowatz					} else {
37752a38012Sejakowatz						entry = entry->next;
37852a38012Sejakowatz					}
37952a38012Sejakowatz				}
38052a38012Sejakowatz				return B_OK;
38152a38012Sejakowatz			}
38252a38012Sejakowatz
38352a38012Sejakowatz		case BTimedEventQueue::B_AFTER_TIME:
38452a38012Sejakowatz			for (entry = GetStart_AfterTime(eventTime, inclusive); entry; ) {
38552a38012Sejakowatz				if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
38652a38012Sejakowatz					action = (*hook)(&entry->event, context);
38752a38012Sejakowatz					switch (action) {
388332cc6bcSAxel Dörfler						case BTimedEventQueue::B_DONE:
38952a38012Sejakowatz							return B_OK;
39052a38012Sejakowatz						case BTimedEventQueue::B_REMOVE_EVENT:
39152a38012Sejakowatz							CleanupEvent(&entry->event);
39252a38012Sejakowatz							remove = entry;
39352a38012Sejakowatz							entry = entry->next;
39452a38012Sejakowatz							RemoveEntry(remove);
39552a38012Sejakowatz							break;
39652a38012Sejakowatz						case BTimedEventQueue::B_NO_ACTION:
39752a38012Sejakowatz						case BTimedEventQueue::B_RESORT_QUEUE:
39852a38012Sejakowatz						default:
39952a38012Sejakowatz							entry = entry->next;
40052a38012Sejakowatz							break;
40152a38012Sejakowatz					}
40252a38012Sejakowatz				} else {
40352a38012Sejakowatz					entry = entry->next;
40452a38012Sejakowatz				}
40552a38012Sejakowatz			}
40652a38012Sejakowatz			return B_OK;
40752a38012Sejakowatz	}
40852a38012Sejakowatz
40952a38012Sejakowatz	return B_ERROR;
41052a38012Sejakowatz}
41152a38012Sejakowatz
412332cc6bcSAxel Dörfler
41352a38012Sejakowatzstatus_t
41452a38012Sejakowatz_event_queue_imp::FlushEvents(bigtime_t eventTime,
41552a38012Sejakowatz							  BTimedEventQueue::time_direction direction,
41652a38012Sejakowatz							  bool inclusive,
41752a38012Sejakowatz							  int32 eventType)
41852a38012Sejakowatz{
41952a38012Sejakowatz	event_queue_entry *end;
42052a38012Sejakowatz	event_queue_entry *entry;
42152a38012Sejakowatz	event_queue_entry *remove;
42252a38012Sejakowatz
42352a38012Sejakowatz	BAutolock lock(fLock);
42452a38012Sejakowatz
42552a38012Sejakowatz	switch (direction) {
42652a38012Sejakowatz		case BTimedEventQueue::B_ALWAYS:
42752a38012Sejakowatz			for (entry = fFirstEntry; entry; ) {
42852a38012Sejakowatz				if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
42952a38012Sejakowatz					CleanupEvent(&entry->event);
43052a38012Sejakowatz					remove = entry;
43152a38012Sejakowatz					entry = entry->next;
43252a38012Sejakowatz					RemoveEntry(remove);
43352a38012Sejakowatz				} else {
43452a38012Sejakowatz					entry = entry->next;
43552a38012Sejakowatz				}
43652a38012Sejakowatz			}
43752a38012Sejakowatz			return B_OK;
43852a38012Sejakowatz
43952a38012Sejakowatz		case BTimedEventQueue::B_BEFORE_TIME:
44052a38012Sejakowatz			end = GetEnd_BeforeTime(eventTime, inclusive);
44152a38012Sejakowatz			if (end == NULL)
44252a38012Sejakowatz				return B_OK;
44352a38012Sejakowatz			end = end->next;
44452a38012Sejakowatz			for (entry = fFirstEntry; entry != end; ) {
44552a38012Sejakowatz				if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
44652a38012Sejakowatz					CleanupEvent(&entry->event);
44752a38012Sejakowatz					remove = entry;
44852a38012Sejakowatz					entry = entry->next;
44952a38012Sejakowatz					RemoveEntry(remove);
45052a38012Sejakowatz				} else {
45152a38012Sejakowatz					entry = entry->next;
45252a38012Sejakowatz				}
45352a38012Sejakowatz			}
45452a38012Sejakowatz			return B_OK;
45552a38012Sejakowatz
45652a38012Sejakowatz		case BTimedEventQueue::B_AT_TIME:
45752a38012Sejakowatz			{
45852a38012Sejakowatz				bool found_time = false;
45952a38012Sejakowatz				for (entry = fFirstEntry; entry; ) {
46052a38012Sejakowatz					if (eventTime == entry->event.event_time) {
46152a38012Sejakowatz						found_time = true;
46252a38012Sejakowatz						if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
46352a38012Sejakowatz							CleanupEvent(&entry->event);
46452a38012Sejakowatz							remove = entry;
46552a38012Sejakowatz							entry = entry->next;
46652a38012Sejakowatz							RemoveEntry(remove);
46752a38012Sejakowatz						} else {
46852a38012Sejakowatz							entry = entry->next;
46952a38012Sejakowatz						}
47052a38012Sejakowatz					} else if (found_time) {
47152a38012Sejakowatz						break;
47252a38012Sejakowatz					} else {
47352a38012Sejakowatz						entry = entry->next;
47452a38012Sejakowatz					}
47552a38012Sejakowatz				}
47652a38012Sejakowatz				return B_OK;
47752a38012Sejakowatz			}
47852a38012Sejakowatz
47952a38012Sejakowatz		case BTimedEventQueue::B_AFTER_TIME:
48052a38012Sejakowatz			for (entry = GetStart_AfterTime(eventTime, inclusive); entry; ) {
48152a38012Sejakowatz				if (eventType == BTimedEventQueue::B_ANY_EVENT || eventType == entry->event.type) {
48252a38012Sejakowatz					CleanupEvent(&entry->event);
48352a38012Sejakowatz					remove = entry;
48452a38012Sejakowatz					entry = entry->next;
48552a38012Sejakowatz					RemoveEntry(remove);
48652a38012Sejakowatz				} else {
48752a38012Sejakowatz					entry = entry->next;
48852a38012Sejakowatz				}
48952a38012Sejakowatz			}
49052a38012Sejakowatz			return B_OK;
49152a38012Sejakowatz	}
49252a38012Sejakowatz
49352a38012Sejakowatz	return B_ERROR;
49452a38012Sejakowatz}
49552a38012Sejakowatz
49652a38012Sejakowatz
49752a38012Sejakowatzvoid
49852a38012Sejakowatz_event_queue_imp::SetCleanupHook(BTimedEventQueue::cleanup_hook hook, void *context)
49952a38012Sejakowatz{
50052a38012Sejakowatz	BAutolock lock(fLock);
50152a38012Sejakowatz	fCleanupHookContext = context;
50252a38012Sejakowatz	fCleanupHook = hook;
50352a38012Sejakowatz}
50452a38012Sejakowatz
50552a38012Sejakowatz
506332cc6bcSAxel Dörflervoid
50752a38012Sejakowatz_event_queue_imp::RemoveEntry(event_queue_entry *entry)
50852a38012Sejakowatz{
50952a38012Sejakowatz	//remove the entry from double-linked list
51052a38012Sejakowatz	//and delete it
51152a38012Sejakowatz	if (entry->prev != NULL)
51252a38012Sejakowatz		(entry->prev)->next = entry->next;
51352a38012Sejakowatz	if (entry->next != NULL)
51452a38012Sejakowatz		(entry->next)->prev = entry->prev;
51552a38012Sejakowatz	if (entry == fFirstEntry) {
51652a38012Sejakowatz		fFirstEntry = entry->next;
51752a38012Sejakowatz		if (fFirstEntry != NULL)
51852a38012Sejakowatz			fFirstEntry->prev = NULL;
51952a38012Sejakowatz	}
52052a38012Sejakowatz	if (entry == fLastEntry) {
52152a38012Sejakowatz		fLastEntry = entry->prev;
52252a38012Sejakowatz		if (fLastEntry != NULL)
52352a38012Sejakowatz			fLastEntry->next = NULL;
52452a38012Sejakowatz	}
52552a38012Sejakowatz	delete entry;
52652a38012Sejakowatz	fEventCount--;
52752a38012Sejakowatz	ASSERT(fEventCount >= 0);
52852a38012Sejakowatz	ASSERT(fEventCount != 0 || ((fFirstEntry == NULL) && (fLastEntry == NULL)));
52952a38012Sejakowatz}
53052a38012Sejakowatz
53152a38012Sejakowatz
532332cc6bcSAxel Dörflervoid
53352a38012Sejakowatz_event_queue_imp::CleanupEvent(media_timed_event *event)
53452a38012Sejakowatz{
53552a38012Sejakowatz	//perform the cleanup action required
53652a38012Sejakowatz	//when deleting an event from the queue
53752a38012Sejakowatz
53852a38012Sejakowatz	//BeBook says:
539332cc6bcSAxel Dörfler	//	Each event has a cleanup flag associated with it that indicates
540332cc6bcSAxel Dörfler	//  what sort of special action needs to be performed when the event is
541332cc6bcSAxel Dörfler	//  removed from the queue. If this value is B_NO_CLEANUP, nothing is done.
54252a38012Sejakowatz	//  If it's B_RECYCLE, and the event is a B_HANDLE_BUFFER event, BTimedEventQueue
543332cc6bcSAxel Dörfler	//  will automatically recycle the buffer associated with the event.
544332cc6bcSAxel Dörfler	//  If the cleanup flag is B_DELETE or is B_USER_CLEANUP or greater,
545332cc6bcSAxel Dörfler	//  the cleanup hook function will be called.
54652a38012Sejakowatz	//and:
54752a38012Sejakowatz	//  cleanup hook function specified by hook to be called for events
548332cc6bcSAxel Dörfler	//  as they're removed from the queue. The hook will be called only
549332cc6bcSAxel Dörfler	//  for events with cleanup_flag values of B_DELETE or B_USER_CLEANUP or greater.
55052a38012Sejakowatz	//and:
551332cc6bcSAxel Dörfler	//  These values define how BTimedEventQueue should handle removing
552332cc6bcSAxel Dörfler	//  events from the queue. If the flag is B_USER_CLEANUP or greater,
553332cc6bcSAxel Dörfler	//  the cleanup hook function is called when the event is removed.
55452a38012Sejakowatz	//Problems:
555332cc6bcSAxel Dörfler	//  B_DELETE is a keyboard code! (seems to have existed in early
55652a38012Sejakowatz	//  sample code as a cleanup flag)
55752a38012Sejakowatz	//
55852a38012Sejakowatz	//  exiting cleanup flags are:
55952a38012Sejakowatz	//		B_NO_CLEANUP = 0,
56052a38012Sejakowatz	//		B_RECYCLE_BUFFER,		// recycle buffers handled by BTimedEventQueue
56152a38012Sejakowatz	//		B_EXPIRE_TIMER,			// call TimerExpired() on the event->data
56252a38012Sejakowatz	//		B_USER_CLEANUP = 0x4000	// others go to the cleanup func
563332cc6bcSAxel Dörfler	//
564332cc6bcSAxel Dörfler
56552a38012Sejakowatz	if (event->cleanup == BTimedEventQueue::B_NO_CLEANUP) {
56652a38012Sejakowatz		// do nothing
5672303600aSDario Casalinuovo	} else if (event->type == BTimedEventQueue::B_HANDLE_BUFFER
5682303600aSDario Casalinuovo			&& event->cleanup == BTimedEventQueue::B_RECYCLE_BUFFER) {
56952a38012Sejakowatz		((BBuffer *)event->pointer)->Recycle();
5709bedd42cSbeveloper		DEBUG_ONLY(*const_cast<void **>(&event->pointer) = NULL);
57152a38012Sejakowatz	} else if (event->cleanup == BTimedEventQueue::B_EXPIRE_TIMER) {
5722303600aSDario Casalinuovo		// do nothing, called in BMediaEventLooper::DispatchEvent
5732303600aSDario Casalinuovo	} else if (event->cleanup == B_DELETE
5742303600aSDario Casalinuovo			|| event->cleanup >= BTimedEventQueue::B_USER_CLEANUP) {
57552a38012Sejakowatz		if (fCleanupHook)
57652a38012Sejakowatz			(*fCleanupHook)(event,fCleanupHookContext);
57752a38012Sejakowatz	} else {
578332cc6bcSAxel Dörfler		ERROR("BTimedEventQueue cleanup unhandled! type = %" B_PRId32
579332cc6bcSAxel Dörfler			", cleanup = %" B_PRId32 "\n", event->type, event->cleanup);
58052a38012Sejakowatz	}
58152a38012Sejakowatz}
58252a38012Sejakowatz
58352a38012Sejakowatz
58452a38012Sejakowatz_event_queue_imp::event_queue_entry *
58552a38012Sejakowatz_event_queue_imp::GetEnd_BeforeTime(bigtime_t eventTime, bool inclusive)
58652a38012Sejakowatz{
58752a38012Sejakowatz	event_queue_entry *entry;
588332cc6bcSAxel Dörfler
58952a38012Sejakowatz	entry = fLastEntry;
59052a38012Sejakowatz	while (entry) {
59152a38012Sejakowatz		if ((entry->event.event_time > eventTime) || (!inclusive && entry->event.event_time == eventTime))
59252a38012Sejakowatz			entry = entry->prev;
59352a38012Sejakowatz		else
59452a38012Sejakowatz			break;
59552a38012Sejakowatz	}
59652a38012Sejakowatz	return entry;
59752a38012Sejakowatz}
59852a38012Sejakowatz
59952a38012Sejakowatz
60052a38012Sejakowatz_event_queue_imp::event_queue_entry *
60152a38012Sejakowatz_event_queue_imp::GetStart_AfterTime(bigtime_t eventTime, bool inclusive)
60252a38012Sejakowatz{
60352a38012Sejakowatz	event_queue_entry *entry;
604332cc6bcSAxel Dörfler
60552a38012Sejakowatz	entry = fFirstEntry;
60652a38012Sejakowatz	while (entry) {
60752a38012Sejakowatz		if ((entry->event.event_time < eventTime) || (!inclusive && entry->event.event_time == eventTime))
60852a38012Sejakowatz			entry = entry->next;
60952a38012Sejakowatz		else
61052a38012Sejakowatz			break;
61152a38012Sejakowatz	}
61252a38012Sejakowatz	return entry;
61352a38012Sejakowatz}
61452a38012Sejakowatz
61552a38012Sejakowatz
61652a38012Sejakowatz#if DEBUG > 1
61752a38012Sejakowatzvoid
61852a38012Sejakowatz_event_queue_imp::Dump() const
61952a38012Sejakowatz{
6202ceb090fSDario Casalinuovo	TRACE("fEventCount = %" B_PRId32 "\n", fEventCount);
621f4ba347bSDario Casalinuovo	TRACE("fFirstEntry = 0x%p\n", (void*)fFirstEntry);
622f4ba347bSDario Casalinuovo	TRACE("fLastEntry  = 0x%p\n", (void*)fLastEntry);
62352a38012Sejakowatz	for (event_queue_entry *entry = fFirstEntry; entry; entry = entry->next) {
624f4ba347bSDario Casalinuovo		TRACE("entry = 0x%p\n", (void*)entry);
625f4ba347bSDario Casalinuovo		TRACE("  entry.prev = 0x%p\n", (void*)entry->prev);
626f4ba347bSDario Casalinuovo		TRACE("  entry.next = 0x%p\n", (void*)entry->next);
627f4ba347bSDario Casalinuovo		TRACE("  entry.event.event_time = %" B_PRId64 "\n",
628f4ba347bSDario Casalinuovo			entry->event.event_time);
62952a38012Sejakowatz	}
63052a38012Sejakowatz}
63152a38012Sejakowatz#endif
632