tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / media / MediaEventLooper.cpp
blob0ce44f56f8e1ce615d8bf709752e08263c38dcc0
1 /*
2 * Copyright (c) 2002, 2003 Marcus Overhagen <Marcus@Overhagen.de>
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files or portions
6 * thereof (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so, subject
10 * to the following conditions:
12 * * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright notice
16 * in the binary, as well as this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided with
18 * the distribution.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
30 #include <MediaEventLooper.h>
31 #include <TimeSource.h>
32 #include <scheduler.h>
33 #include <Buffer.h>
34 #include <ServerInterface.h>
35 #include "debug.h"
37 /*************************************************************
38 * protected BMediaEventLooper
39 *************************************************************/
41 /* virtual */
42 BMediaEventLooper::~BMediaEventLooper()
44 CALLED();
46 // don't call Quit(); here, except if the user was stupid
47 if (fControlThread != -1) {
48 printf("You MUST call BMediaEventLooper::Quit() in your destructor!\n");
49 Quit();
53 /* explicit */
54 BMediaEventLooper::BMediaEventLooper(uint32 apiVersion) :
55 BMediaNode("called by BMediaEventLooper"),
56 fControlThread(-1),
57 fCurrentPriority(B_URGENT_PRIORITY),
58 fSetPriority(B_URGENT_PRIORITY),
59 fRunState(B_UNREGISTERED),
60 fEventLatency(0),
61 fSchedulingLatency(0),
62 fBufferDuration(0),
63 fOfflineTime(0),
64 fApiVersion(apiVersion)
66 CALLED();
67 fEventQueue.SetCleanupHook(BMediaEventLooper::_CleanUpEntry, this);
68 fRealTimeQueue.SetCleanupHook(BMediaEventLooper::_CleanUpEntry, this);
71 /* virtual */ void
72 BMediaEventLooper::NodeRegistered()
74 CALLED();
75 // Calling Run() should be done by the derived class,
76 // at least that's how it is documented by the BeBook.
77 // It appears that BeOS R5 called it here. Calling Run()
78 // twice doesn't hurt, and some nodes need it to be called here.
79 Run();
83 /* virtual */ void
84 BMediaEventLooper::Start(bigtime_t performance_time)
86 CALLED();
87 // This hook function is called when a node is started
88 // by a call to the BMediaRoster. The specified
89 // performanceTime, the time at which the node
90 // should start running, may be in the future.
91 fEventQueue.AddEvent(media_timed_event(performance_time, BTimedEventQueue::B_START));
95 /* virtual */ void
96 BMediaEventLooper::Stop(bigtime_t performance_time,
97 bool immediate)
99 CALLED();
100 // This hook function is called when a node is stopped
101 // by a call to the BMediaRoster. The specified performanceTime,
102 // the time at which the node should stop, may be in the future.
103 // If immediate is true, your node should ignore the performanceTime
104 // value and synchronously stop performance. When Stop() returns,
105 // you're promising not to write into any BBuffers you may have
106 // received from your downstream consumers, and you promise not
107 // to send any more buffers until Start() is called again.
109 if (immediate) {
110 // always be sure to add to the front of the queue so we can make sure it is
111 // handled before any buffers are sent!
112 performance_time = 0;
114 fEventQueue.AddEvent(media_timed_event(performance_time, BTimedEventQueue::B_STOP));
118 /* virtual */ void
119 BMediaEventLooper::Seek(bigtime_t media_time,
120 bigtime_t performance_time)
122 CALLED();
123 // This hook function is called when a node is asked to seek to
124 // the specified mediaTime by a call to the BMediaRoster.
125 // The specified performanceTime, the time at which the node
126 // should begin the seek operation, may be in the future.
127 fEventQueue.AddEvent(media_timed_event(performance_time, BTimedEventQueue::B_SEEK, NULL,
128 BTimedEventQueue::B_NO_CLEANUP, 0, media_time, NULL));
132 /* virtual */ void
133 BMediaEventLooper::TimeWarp(bigtime_t at_real_time,
134 bigtime_t to_performance_time)
136 CALLED();
137 // This hook function is called when the time source to which the
138 // node is slaved is repositioned (via a seek operation) such that
139 // there will be a sudden jump in the performance time progression
140 // as seen by the node. The to_performance_time argument indicates
141 // the new performance time; the change should occur at the real
142 // time specified by the at_real_time argument.
144 // place in the realtime queue
145 fRealTimeQueue.AddEvent(media_timed_event(at_real_time, BTimedEventQueue::B_WARP,
146 NULL, BTimedEventQueue::B_NO_CLEANUP, 0, to_performance_time, NULL));
148 // BeBook: Your implementation of TimeWarp() should call through to BMediaNode::TimeWarp()
149 // BeBook: as well as all other inherited forms of TimeWarp()
150 // XXX should we do this here?
151 BMediaNode::TimeWarp(at_real_time, to_performance_time);
155 /* virtual */ status_t
156 BMediaEventLooper::AddTimer(bigtime_t at_performance_time,
157 int32 cookie)
159 CALLED();
161 media_timed_event event(at_performance_time,
162 BTimedEventQueue::B_TIMER, NULL,
163 BTimedEventQueue::B_EXPIRE_TIMER);
164 event.data = cookie;
165 return EventQueue()->AddEvent(event);
169 /* virtual */ void
170 BMediaEventLooper::SetRunMode(run_mode mode)
172 CALLED();
173 // The SetRunMode() hook function is called when someone requests that your node's run mode be changed.
175 // bump or reduce priority when switching from/to offline run mode
176 int32 priority;
177 priority = (mode == B_OFFLINE) ? min_c(B_NORMAL_PRIORITY, fSetPriority) : fSetPriority;
178 if (priority != fCurrentPriority) {
179 fCurrentPriority = priority;
180 if (fControlThread > 0) {
181 set_thread_priority(fControlThread, fCurrentPriority);
182 fSchedulingLatency = estimate_max_scheduling_latency(fControlThread);
183 printf("BMediaEventLooper: SchedulingLatency is %" B_PRId64 "\n",
184 fSchedulingLatency);
188 BMediaNode::SetRunMode(mode);
192 /* virtual */ void
193 BMediaEventLooper::CleanUpEvent(const media_timed_event *event)
195 CALLED();
196 // Implement this function to clean up after custom events you've created
197 // and added to your queue. It's called when a custom event is removed from
198 // the queue, to let you handle any special tidying-up that the event might require.
202 /* virtual */ bigtime_t
203 BMediaEventLooper::OfflineTime()
205 CALLED();
206 return fOfflineTime;
210 /* virtual */ void
211 BMediaEventLooper::ControlLoop()
213 CALLED();
215 bool is_realtime = false;
216 status_t err;
217 bigtime_t latency;
218 bigtime_t waituntil;
219 bigtime_t lateness;
220 for (;;) {
221 // while there are no events or it is not time for the earliest event,
222 // process messages using WaitForMessages. Whenever this funtion times out,
223 // we need to handle the next event
224 for (;;) {
225 if (RunState() == B_QUITTING)
226 return;
227 // BMediaEventLooper compensates your performance time by adding the event latency
228 // (see SetEventLatency()) and the scheduling latency (or, for real-time events,
229 // only the scheduling latency).
231 latency = fEventLatency + fSchedulingLatency;
232 waituntil = B_INFINITE_TIMEOUT;
233 if (fEventQueue.HasEvents()) {
234 const media_timed_event *firstEvent = fEventQueue.FirstEvent();
235 waituntil = TimeSource()->RealTimeFor(firstEvent->event_time, latency);
236 is_realtime = false;
237 lateness = firstEvent->queued_time - waituntil;
238 if (lateness > 0) {
239 // if (lateness > 1000)
240 // printf("node %02ld handling %12Ld at %12Ld -- %Ld late, queued at %Ld now %12Ld \n",
241 // ID(), fEventQueue.FirstEventTime(), TimeSource()->Now(), lateness,
242 // firstEvent->queued_time, TimeSource()->RealTime());
243 is_realtime = false;
244 break;
246 // printf("node %02ld waiting for %12Ld that will happen at %12Ld\n", ID(), fEventQueue.FirstEventTime(), waituntil);
248 if (fRealTimeQueue.HasEvents()) {
249 const media_timed_event *firstEvent = fRealTimeQueue.FirstEvent();
250 bigtime_t temp;
251 temp = firstEvent->event_time - fSchedulingLatency;
252 lateness = firstEvent->queued_time - temp;
253 if (lateness > 0) {
254 is_realtime = true;
255 break;
257 if (temp < waituntil) {
258 waituntil = temp;
259 is_realtime = true;
262 lateness = 0; // remove any extraneous value if we get this far
263 err = WaitForMessage(waituntil);
264 if (err == B_TIMED_OUT)
265 break;
267 /// we have timed out - so handle the next event
268 media_timed_event event;
269 if (is_realtime)
270 err = fRealTimeQueue.RemoveFirstEvent(&event);
271 else
272 err = fEventQueue.RemoveFirstEvent(&event);
274 // printf("node %02ld handling %12Ld at %12Ld\n", ID(), event.event_time, TimeSource()->Now());
276 if (err == B_OK) DispatchEvent(&event, lateness, is_realtime);
281 thread_id
282 BMediaEventLooper::ControlThread()
284 CALLED();
285 return fControlThread;
288 /*************************************************************
289 * protected BMediaEventLooper
290 *************************************************************/
293 BTimedEventQueue *
294 BMediaEventLooper::EventQueue()
296 CALLED();
297 return &fEventQueue;
301 BTimedEventQueue *
302 BMediaEventLooper::RealTimeQueue()
304 CALLED();
305 return &fRealTimeQueue;
309 int32
310 BMediaEventLooper::Priority() const
312 CALLED();
313 return fCurrentPriority;
317 int32
318 BMediaEventLooper::RunState() const
320 PRINT(6, "CALLED BMediaEventLooper::RunState()\n");
321 return fRunState;
325 bigtime_t
326 BMediaEventLooper::EventLatency() const
328 CALLED();
329 return fEventLatency;
333 bigtime_t
334 BMediaEventLooper::BufferDuration() const
336 CALLED();
337 return fBufferDuration;
341 bigtime_t
342 BMediaEventLooper::SchedulingLatency() const
344 CALLED();
345 return fSchedulingLatency;
349 status_t
350 BMediaEventLooper::SetPriority(int32 priority)
352 CALLED();
354 // clamp to a valid value
355 if (priority < 5)
356 priority = 5;
358 if (priority > 120)
359 priority = 120;
361 fSetPriority = priority;
362 fCurrentPriority = (RunMode() == B_OFFLINE) ? min_c(B_NORMAL_PRIORITY, fSetPriority) : fSetPriority;
364 if (fControlThread > 0) {
365 set_thread_priority(fControlThread, fCurrentPriority);
366 fSchedulingLatency = estimate_max_scheduling_latency(fControlThread);
367 printf("BMediaEventLooper: SchedulingLatency is %" B_PRId64 "\n",
368 fSchedulingLatency);
371 return B_OK;
375 void
376 BMediaEventLooper::SetRunState(run_state state)
378 CALLED();
380 // don't allow run state changes while quitting,
381 // also needed for correct terminating of the ControlLoop()
382 if (fRunState == B_QUITTING && state != B_TERMINATED)
383 return;
385 fRunState = state;
389 void
390 BMediaEventLooper::SetEventLatency(bigtime_t latency)
392 CALLED();
393 // clamp to a valid value
394 if (latency < 0)
395 latency = 0;
397 fEventLatency = latency;
398 write_port_etc(ControlPort(), GENERAL_PURPOSE_WAKEUP, 0, 0, B_TIMEOUT, 0);
402 void
403 BMediaEventLooper::SetBufferDuration(bigtime_t duration)
405 CALLED();
406 fBufferDuration = duration;
410 void
411 BMediaEventLooper::SetOfflineTime(bigtime_t offTime)
413 CALLED();
414 fOfflineTime = offTime;
418 void
419 BMediaEventLooper::Run()
421 CALLED();
423 if (fControlThread != -1)
424 return; // thread already running
426 // until now, the run state is B_UNREGISTERED, but we need to start in B_STOPPED state.
427 SetRunState(B_STOPPED);
429 char threadName[32];
430 sprintf(threadName, "%.20s control", Name());
431 fControlThread = spawn_thread(_ControlThreadStart, threadName, fCurrentPriority, this);
432 resume_thread(fControlThread);
434 // get latency information
435 fSchedulingLatency = estimate_max_scheduling_latency(fControlThread);
439 void
440 BMediaEventLooper::Quit()
442 CALLED();
444 if (fRunState == B_TERMINATED)
445 return;
447 SetRunState(B_QUITTING);
448 close_port(ControlPort());
449 if (fControlThread != -1) {
450 status_t err;
451 wait_for_thread(fControlThread, &err);
452 fControlThread = -1;
454 SetRunState(B_TERMINATED);
458 void
459 BMediaEventLooper::DispatchEvent(const media_timed_event *event,
460 bigtime_t lateness,
461 bool realTimeEvent)
463 PRINT(6, "CALLED BMediaEventLooper::DispatchEvent()\n");
465 HandleEvent(event, lateness, realTimeEvent);
467 switch (event->type) {
468 case BTimedEventQueue::B_START:
469 SetRunState(B_STARTED);
470 break;
472 case BTimedEventQueue::B_STOP:
473 SetRunState(B_STOPPED);
474 break;
476 case BTimedEventQueue::B_SEEK:
477 /* nothing */
478 break;
480 case BTimedEventQueue::B_WARP:
481 /* nothing */
482 break;
484 case BTimedEventQueue::B_TIMER:
485 TimerExpired(event->event_time, event->data);
486 break;
488 default:
489 break;
492 _DispatchCleanUp(event);
495 /*************************************************************
496 * private BMediaEventLooper
497 *************************************************************/
500 /* static */ int32
501 BMediaEventLooper::_ControlThreadStart(void *arg)
503 CALLED();
504 ((BMediaEventLooper *)arg)->SetRunState(B_STOPPED);
505 ((BMediaEventLooper *)arg)->ControlLoop();
506 ((BMediaEventLooper *)arg)->SetRunState(B_QUITTING);
507 return 0;
511 /* static */ void
512 BMediaEventLooper::_CleanUpEntry(const media_timed_event *event,
513 void *context)
515 PRINT(6, "CALLED BMediaEventLooper::_CleanUpEntry()\n");
516 ((BMediaEventLooper *)context)->_DispatchCleanUp(event);
520 void
521 BMediaEventLooper::_DispatchCleanUp(const media_timed_event *event)
523 PRINT(6, "CALLED BMediaEventLooper::_DispatchCleanUp()\n");
525 // this function to clean up after custom events you've created
526 if (event->cleanup >= BTimedEventQueue::B_USER_CLEANUP)
527 CleanUpEvent(event);
531 // unimplemented
532 BMediaEventLooper::BMediaEventLooper(const BMediaEventLooper &)
533 BMediaEventLooper &BMediaEventLooper::operator=(const BMediaEventLooper &)
536 /*************************************************************
537 * protected BMediaEventLooper
538 *************************************************************/
541 status_t
542 BMediaEventLooper::DeleteHook(BMediaNode *node)
544 CALLED();
545 // this is the DeleteHook that gets called by the media server
546 // before the media node is deleted
547 Quit();
548 return BMediaNode::DeleteHook(node);
551 /*************************************************************
552 * private BMediaEventLooper
553 *************************************************************/
555 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_0(int32 arg,...) { return B_ERROR; }
556 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_1(int32 arg,...) { return B_ERROR; }
557 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_2(int32 arg,...) { return B_ERROR; }
558 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_3(int32 arg,...) { return B_ERROR; }
559 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_4(int32 arg,...) { return B_ERROR; }
560 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_5(int32 arg,...) { return B_ERROR; }
561 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_6(int32 arg,...) { return B_ERROR; }
562 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_7(int32 arg,...) { return B_ERROR; }
563 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_8(int32 arg,...) { return B_ERROR; }
564 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_9(int32 arg,...) { return B_ERROR; }
565 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_10(int32 arg,...) { return B_ERROR; }
566 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_11(int32 arg,...) { return B_ERROR; }
567 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_12(int32 arg,...) { return B_ERROR; }
568 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_13(int32 arg,...) { return B_ERROR; }
569 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_14(int32 arg,...) { return B_ERROR; }
570 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_15(int32 arg,...) { return B_ERROR; }
571 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_16(int32 arg,...) { return B_ERROR; }
572 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_17(int32 arg,...) { return B_ERROR; }
573 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_18(int32 arg,...) { return B_ERROR; }
574 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_19(int32 arg,...) { return B_ERROR; }
575 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_20(int32 arg,...) { return B_ERROR; }
576 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_21(int32 arg,...) { return B_ERROR; }
577 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_22(int32 arg,...) { return B_ERROR; }
578 status_t BMediaEventLooper::_Reserved_BMediaEventLooper_23(int32 arg,...) { return B_ERROR; }