xref: /haiku/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.cpp (revision ed6250c95736c0b55da79d6e9dd01369532260c0)
1 // MediaDemultiplexerNode.cpp
2 //
3 // Andrew Bachmann, 2002
4 //
5 // The MediaDemultiplexerNode class
6 // takes a multistream input and supplies
7 // the individual constituent streams as
8 // the output.
9 
10 #include <MediaDefs.h>
11 #include <MediaNode.h>
12 #include <MediaAddOn.h>
13 #include <BufferConsumer.h>
14 #include <BufferProducer.h>
15 #include <MediaEventLooper.h>
16 #include <Errors.h>
17 #include <BufferGroup.h>
18 #include <TimeSource.h>
19 #include <Buffer.h>
20 #include <limits.h>
21 
22 #include "MediaDemultiplexerNode.h"
23 #include "misc.h"
24 
25 #include <stdio.h>
26 #include <string.h>
27 
28 // -------------------------------------------------------- //
29 // ctor/dtor
30 // -------------------------------------------------------- //
31 
32 MediaDemultiplexerNode::~MediaDemultiplexerNode(void)
33 {
34 	fprintf(stderr,"MediaDemultiplexerNode::~MediaDemultiplexerNode\n");
35 	// Stop the BMediaEventLooper thread
36 	Quit();
37 }
38 
39 MediaDemultiplexerNode::MediaDemultiplexerNode(
40 				const flavor_info * info = 0,
41 				BMessage * config = 0,
42 				BMediaAddOn * addOn = 0)
43 	: BMediaNode("MediaDemultiplexerNode"),
44 	  BMediaEventLooper(),
45   	  BBufferConsumer(B_MEDIA_MULTISTREAM),
46   	  BBufferProducer(B_MEDIA_UNKNOWN_TYPE) // no B_MEDIA_ANY
47 {
48 	fprintf(stderr,"MediaDemultiplexerNode::MediaDemultiplexerNode\n");
49 	// keep our creator around for AddOn calls later
50 	fAddOn = addOn;
51 	// null out our latency estimates
52 	fDownstreamLatency = 0;
53 	fInternalLatency = 0;
54 	// don't overwrite available space, and be sure to terminate
55 	strncpy(input.name,"Demultiplexer Input",B_MEDIA_NAME_LENGTH-1);
56 	input.name[B_MEDIA_NAME_LENGTH-1] = '\0';
57 	// initialize the input
58 	input.node = media_node::null;               // until registration
59 	input.source = media_source::null;
60 	input.destination = media_destination::null; // until registration
61 	GetInputFormat(&input.format);
62 
63 	outputs.empty();
64 	// outputs initialized after we connect,
65 	// find a suitable extractor,
66 	// and it tells us the ouputs
67 
68 	fInitCheckStatus = B_OK;
69 }
70 
71 status_t MediaDemultiplexerNode::InitCheck(void) const
72 {
73 	fprintf(stderr,"MediaDemultiplexerNode::InitCheck\n");
74 	return fInitCheckStatus;
75 }
76 
77 status_t MediaDemultiplexerNode::GetConfigurationFor(
78 				BMessage * into_message)
79 {
80 	fprintf(stderr,"MediaDemultiplexerNode::GetConfigurationFor\n");
81 	return B_OK;
82 }
83 
84 // -------------------------------------------------------- //
85 // implementation of BMediaNode
86 // -------------------------------------------------------- //
87 
88 BMediaAddOn * MediaDemultiplexerNode::AddOn(
89 				int32 * internal_id) const
90 {
91 	fprintf(stderr,"MediaDemultiplexerNode::AddOn\n");
92 	// BeBook says this only gets called if we were in an add-on.
93 	if (fAddOn != 0) {
94 		// If we get a null pointer then we just won't write.
95 		if (internal_id != 0) {
96 			internal_id = 0;
97 		}
98 	}
99 	return fAddOn;
100 }
101 
102 void MediaDemultiplexerNode::Start(
103 				bigtime_t performance_time)
104 {
105 	fprintf(stderr,"MediaDemultiplexerNode::Start(pt=%lld)\n",performance_time);
106 	BMediaEventLooper::Start(performance_time);
107 }
108 
109 void MediaDemultiplexerNode::Stop(
110 				bigtime_t performance_time,
111 				bool immediate)
112 {
113 	if (immediate) {
114 		fprintf(stderr,"MediaDemultiplexerNode::Stop(pt=%lld,<immediate>)\n",performance_time);
115 	} else {
116 		fprintf(stderr,"MediaDemultiplexerNode::Stop(pt=%lld,<scheduled>)\n",performance_time);
117 	}
118 	BMediaEventLooper::Stop(performance_time,immediate);
119 }
120 
121 void MediaDemultiplexerNode::Seek(
122 				bigtime_t media_time,
123 				bigtime_t performance_time)
124 {
125 	fprintf(stderr,"MediaDemultiplexerNode::Seek(mt=%lld,pt=%lld)\n",media_time,performance_time);
126 	BMediaEventLooper::Seek(media_time,performance_time);
127 }
128 
129 void MediaDemultiplexerNode::SetRunMode(
130 				run_mode mode)
131 {
132 	fprintf(stderr,"MediaDemultiplexerNode::SetRunMode(%i)\n",mode);
133 	BMediaEventLooper::SetRunMode(mode);
134 }
135 
136 void MediaDemultiplexerNode::TimeWarp(
137 				bigtime_t at_real_time,
138 				bigtime_t to_performance_time)
139 {
140 	fprintf(stderr,"MediaDemultiplexerNode::TimeWarp(rt=%lld,pt=%lld)\n",at_real_time,to_performance_time);
141 	BMediaEventLooper::TimeWarp(at_real_time,to_performance_time);
142 }
143 
144 void MediaDemultiplexerNode::Preroll(void)
145 {
146 	fprintf(stderr,"MediaDemultiplexerNode::Preroll\n");
147 	// XXX:Performance opportunity
148 	BMediaNode::Preroll();
149 }
150 
151 void MediaDemultiplexerNode::SetTimeSource(
152 				BTimeSource * time_source)
153 {
154 	fprintf(stderr,"MediaDemultiplexerNode::SetTimeSource\n");
155 	BMediaNode::SetTimeSource(time_source);
156 }
157 
158 status_t MediaDemultiplexerNode::HandleMessage(
159 				int32 message,
160 				const void * data,
161 				size_t size)
162 {
163 	fprintf(stderr,"MediaDemultiplexerNode::HandleMessage\n");
164 	status_t status = B_OK;
165 	switch (message) {
166 		// no special messages for now
167 		default:
168 			status = BBufferConsumer::HandleMessage(message,data,size);
169 			if (status == B_OK) {
170 				break;
171 			}
172 			status = BBufferProducer::HandleMessage(message,data,size);
173 			if (status == B_OK) {
174 				break;
175 			}
176 			status = BMediaNode::HandleMessage(message,data,size);
177 			if (status == B_OK) {
178 				break;
179 			}
180 			BMediaNode::HandleBadMessage(message,data,size);
181 			status = B_ERROR;
182 			break;
183 	}
184 	return status;
185 }
186 
187 status_t MediaDemultiplexerNode::RequestCompleted(
188 				const media_request_info & info)
189 {
190 	fprintf(stderr,"MediaDemultiplexerNode::RequestCompleted\n");
191 	return BMediaNode::RequestCompleted(info);
192 }
193 
194 status_t MediaDemultiplexerNode::DeleteHook(
195 				BMediaNode * node)
196 {
197 	fprintf(stderr,"MediaDemultiplexerNode::DeleteHook\n");
198 	return BMediaEventLooper::DeleteHook(node);
199 }
200 
201 void MediaDemultiplexerNode::NodeRegistered(void)
202 {
203 	fprintf(stderr,"MediaDemultiplexerNode::NodeRegistered\n");
204 
205 	// now we can do this
206 	input.node = Node();
207 	input.destination.id = 0;
208 	input.destination.port = input.node.port; // same as ControlPort()
209 
210 	// outputs initialized after we connect,
211 	// find a suitable extractor,
212 	// and it tells us the ouputs
213 
214 	// start the BMediaEventLooper thread
215 	SetPriority(B_REAL_TIME_PRIORITY);
216 	Run();
217 }
218 
219 status_t MediaDemultiplexerNode::GetNodeAttributes(
220 				media_node_attribute * outAttributes,
221 				size_t inMaxCount)
222 {
223 	fprintf(stderr,"MediaDemultiplexerNode::GetNodeAttributes\n");
224 	return BMediaNode::GetNodeAttributes(outAttributes,inMaxCount);
225 }
226 
227 status_t MediaDemultiplexerNode::AddTimer(
228 					bigtime_t at_performance_time,
229 					int32 cookie)
230 {
231 	fprintf(stderr,"MediaDemultiplexerNode::AddTimer\n");
232 	return BMediaEventLooper::AddTimer(at_performance_time,cookie);
233 }
234 
235 // -------------------------------------------------------- //
236 // implemention of BBufferConsumer
237 // -------------------------------------------------------- //
238 
239 // Check to make sure the format is okay, then remove
240 // any wildcards corresponding to our requirements.
241 status_t MediaDemultiplexerNode::AcceptFormat(
242 				const media_destination & dest,
243 				media_format * format)
244 {
245 	fprintf(stderr,"MediaDemultiplexerNode::AcceptFormat\n");
246 	if (format == 0) {
247 		fprintf(stderr,"<- B_BAD_VALUE\n");
248 		return B_BAD_VALUE; // no crashing
249 	}
250 	if (input.destination != dest) {
251 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION");
252 		return B_MEDIA_BAD_DESTINATION; // we only have one input so that better be it
253 	}
254 	media_format myFormat;
255 	GetInputFormat(&myFormat);
256 	// Be's format_is_compatible doesn't work,
257 	// so use our format_is_acceptible instead
258 	if (!format_is_acceptible(*format,myFormat)) {
259 		fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n");
260 		return B_MEDIA_BAD_FORMAT;
261 	}
262 	AddRequirements(format);
263 	return B_OK;
264 }
265 
266 status_t MediaDemultiplexerNode::GetNextInput(
267 				int32 * cookie,
268 				media_input * out_input)
269 {
270 	fprintf(stderr,"MediaDemultiplexerNode::GetNextInput\n");
271 	// let's not crash even if they are stupid
272 	if (out_input == 0) {
273 		// no place to write!
274 		fprintf(stderr,"<- B_BAD_VALUE\n");
275 		return B_BAD_VALUE;
276 	}
277 	if (cookie != 0) {
278 		// it's valid but they already got our 1 input
279 		if (*cookie != 0) {
280 			fprintf(stderr,"<- B_ERROR (no more inputs)\n");
281 			return B_ERROR;
282 		}
283 		// so next time they won't get the same input again
284 		*cookie = 1;
285 	}
286 	*out_input = input;
287 	return B_OK;
288 }
289 
290 void MediaDemultiplexerNode::DisposeInputCookie(
291 				int32 cookie)
292 {
293 	fprintf(stderr,"MediaDemultiplexerNode::DisposeInputCookie\n");
294 	// nothing to do since our cookies are just integers
295 	return; // B_OK;
296 }
297 
298 void MediaDemultiplexerNode::BufferReceived(
299 				BBuffer * buffer)
300 {
301 	fprintf(stderr,"MediaDemultiplexerNode::BufferReceived\n");
302 	switch (buffer->Header()->type) {
303 //		case B_MEDIA_PARAMETERS:
304 //			{
305 //			status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed());
306 //			if (status != B_OK) {
307 //				fprintf(stderr,"ApplyParameterData in MediaDemultiplexerNode::BufferReceived failed\n");
308 //			}
309 //			buffer->Recycle();
310 //			}
311 //			break;
312 		case B_MEDIA_MULTISTREAM:
313 			if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) {
314 				fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in MediaDemultiplexerNode::BufferReceived\n");
315 				// XXX: implement this part
316 				buffer->Recycle();
317 			} else {
318 				media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER,
319 										buffer, BTimedEventQueue::B_RECYCLE_BUFFER);
320 				status_t status = EventQueue()->AddEvent(event);
321 				if (status != B_OK) {
322 					fprintf(stderr,"EventQueue()->AddEvent(event) in MediaDemultiplexerNode::BufferReceived failed\n");
323 					buffer->Recycle();
324 				}
325 			}
326 			break;
327 		default:
328 			fprintf(stderr,"unexpected buffer type in MediaDemultiplexerNode::BufferReceived\n");
329 			buffer->Recycle();
330 			break;
331 	}
332 }
333 
334 void MediaDemultiplexerNode::ProducerDataStatus(
335 				const media_destination & for_whom,
336 				int32 status,
337 				bigtime_t at_performance_time)
338 {
339 	fprintf(stderr,"MediaDemultiplexerNode::ProducerDataStatus\n");
340 	if (input.destination != for_whom) {
341 		fprintf(stderr,"invalid destination received in MediaDemultiplexerNode::ProducerDataStatus\n");
342 		return;
343 	}
344 	media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS,
345 			&input, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL);
346 	EventQueue()->AddEvent(event);
347 }
348 
349 status_t MediaDemultiplexerNode::GetLatencyFor(
350 				const media_destination & for_whom,
351 				bigtime_t * out_latency,
352 				media_node_id * out_timesource)
353 {
354 	fprintf(stderr,"MediaDemultiplexerNode::GetLatencyFor\n");
355 	if ((out_latency == 0) || (out_timesource == 0)) {
356 		fprintf(stderr,"<- B_BAD_VALUE\n");
357 		return B_BAD_VALUE;
358 	}
359 	if (input.destination != for_whom) {
360 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
361 		return B_MEDIA_BAD_DESTINATION;
362 	}
363 	*out_latency = EventLatency();
364 	*out_timesource = TimeSource()->ID();
365 	return B_OK;
366 }
367 
368 status_t MediaDemultiplexerNode::Connected(
369 				const media_source & producer,	/* here's a good place to request buffer group usage */
370 				const media_destination & where,
371 				const media_format & with_format,
372 				media_input * out_input)
373 {
374 	fprintf(stderr,"MediaDemultiplexerNode::Connected\n");
375 	if (out_input == 0) {
376 		fprintf(stderr,"<- B_BAD_VALUE\n");
377 		return B_BAD_VALUE; // no crashing
378 	}
379 	if (input.destination != where) {
380 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
381 		return B_MEDIA_BAD_DESTINATION;
382 	}
383 
384 	// find an appropriate extractor to handle this type
385 	fprintf(stderr,"  XXX: no extractors yet\n");
386 
387 	// initialize the outputs here
388 	// provide all the types that the extractor claims
389 	outputs.empty();
390 
391 	// compute the latency or just guess
392 	fInternalLatency = 500; // just guess
393 	fprintf(stderr,"  internal latency guessed = %lld\n",fInternalLatency);
394 
395 	SetEventLatency(fInternalLatency);
396 
397 	// record the agreed upon values
398 	input.source = producer;
399 	input.format = with_format;
400 	*out_input = input;
401 	return B_OK;
402 }
403 
404 void MediaDemultiplexerNode::Disconnected(
405 				const media_source & producer,
406 				const media_destination & where)
407 {
408 	fprintf(stderr,"MediaDemultiplexerNode::Disconnected\n");
409 	if (input.destination != where) {
410 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
411 		return;
412 	}
413 	if (input.source != producer) {
414 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
415 		return;
416 	}
417 	input.source = media_source::null;
418 	GetInputFormat(&input.format);
419 
420 	outputs.empty();
421 }
422 
423 	/* The notification comes from the upstream producer, so he's already cool with */
424 	/* the format; you should not ask him about it in here. */
425 status_t MediaDemultiplexerNode::FormatChanged(
426 				const media_source & producer,
427 				const media_destination & consumer,
428 				int32 change_tag,
429 				const media_format & format)
430 {
431 	fprintf(stderr,"MediaDemultiplexerNode::FormatChanged\n");
432 	if (input.source != producer) {
433 		return B_MEDIA_BAD_SOURCE;
434 	}
435 	if (input.destination != consumer) {
436 		return B_MEDIA_BAD_DESTINATION;
437 	}
438 	// XXX: implement
439 	fprintf(stderr,"  This is because we asked to have the format changed.\n"
440 	               "  Therefore we must switch to the other extractor that\n"
441 	               "  we presumably have ready.");
442 	input.format = format;
443 	return B_OK;
444 }
445 
446 	/* Given a performance time of some previous buffer, retrieve the remembered tag */
447 	/* of the closest (previous or exact) performance time. Set *out_flags to 0; the */
448 	/* idea being that flags can be added later, and the understood flags returned in */
449 	/* *out_flags. */
450 status_t MediaDemultiplexerNode::SeekTagRequested(
451 				const media_destination & destination,
452 				bigtime_t in_target_time,
453 				uint32 in_flags,
454 				media_seek_tag * out_seek_tag,
455 				bigtime_t * out_tagged_time,
456 				uint32 * out_flags)
457 {
458 	fprintf(stderr,"MediaDemultiplexerNode::SeekTagRequested\n");
459 	// XXX: implement this
460 	return BBufferConsumer::SeekTagRequested(destination,in_target_time,in_flags,
461 											out_seek_tag,out_tagged_time,out_flags);
462 }
463 
464 // -------------------------------------------------------- //
465 // implemention of BBufferProducer
466 // -------------------------------------------------------- //
467 
468 // They are asking us to make the first offering.
469 // So, we get a fresh format and then add requirements
470 status_t MediaDemultiplexerNode::FormatSuggestionRequested(
471 				media_type type,
472 				int32 quality,
473 				media_format * format)
474 {
475 	fprintf(stderr,"MediaDemultiplexerNode::FormatSuggestionRequested\n");
476 	if (format == 0) {
477 		fprintf(stderr,"<- B_BAD_VALUE\n");
478 		return B_BAD_VALUE; // no crashing
479 	}
480 	// XXX: how do I pick which stream to supply here?....
481 	//      answer?: get the first compatible stream that is available
482 	fprintf(stderr,"  format suggestion requested not implemented\n");
483 //	if ((type != B_MEDIA_MULTISTREAM) && (type != B_MEDIA_UNKNOWN_TYPE)) {
484 //		fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n");
485 //		return B_MEDIA_BAD_FORMAT;
486 //	}
487 	GetOutputFormat(format);
488 //	AddRequirements(format);
489 
490 	return B_OK;
491 }
492 
493 // They made an offer to us.  We should make sure that the offer is
494 // acceptable, and then we can add any requirements we have on top of
495 // that.  We leave wildcards for anything that we don't care about.
496 status_t MediaDemultiplexerNode::FormatProposal(
497 				const media_source & output_source,
498 				media_format * format)
499 {
500 	fprintf(stderr,"MediaDemultiplexerNode::FormatProposal\n");
501 	// find the information for this output
502 	vector<MediaOutputInfo>::iterator itr;
503 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
504 		if (itr->output.source == output_source) {
505 			break;
506 		}
507 	}
508 	if (itr == outputs.end()) {
509 		// we don't have that output
510 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
511 		return B_MEDIA_BAD_SOURCE;
512 	}
513 	return itr->FormatProposal(format);
514 }
515 
516 // Presumably we have already agreed with them that this format is
517 // okay.  But just in case, we check the offer. (and complain if it
518 // is invalid)  Then as the last thing we do, we get rid of any
519 // remaining wilcards.
520 status_t MediaDemultiplexerNode::FormatChangeRequested(
521 				const media_source & source,
522 				const media_destination & destination,
523 				media_format * io_format,
524 				int32 * _deprecated_)
525 {
526 	fprintf(stderr,"MediaDemultiplexerNode::FormatChangeRequested\n");
527 	// find the information for this output
528 	vector<MediaOutputInfo>::iterator itr;
529 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
530 		if (itr->output.source == source) {
531 			break;
532 		}
533 	}
534 	if (itr == outputs.end()) {
535 		// we don't have that output
536 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
537 		return B_MEDIA_BAD_SOURCE;
538 	}
539 	return itr->FormatChangeRequested(destination,io_format);
540 }
541 
542 status_t MediaDemultiplexerNode::GetNextOutput(	/* cookie starts as 0 */
543 				int32 * cookie,
544 				media_output * out_output)
545 {
546 	fprintf(stderr,"MediaDemultiplexerNode::GetNextOutput\n");
547 	// let's not crash even if they are stupid
548 	if ((out_output == 0) || (cookie == 0)) {
549 		// no place to write!
550 		fprintf(stderr,"<- B_BAD_VALUE\n");
551 		return B_BAD_VALUE;
552 	}
553 	// they want a clean start
554 	if (*cookie == 0) {
555 		*cookie = (int32)outputs.begin();
556 	}
557 	vector<MediaOutputInfo>::iterator itr
558 		= (vector<MediaOutputInfo>::iterator)(*cookie);
559 	// XXX: check here if the vector has been modified.
560 	//      if the iterator is invalid, return an error code??
561 
562 	// they already got our 1 output
563 	if (itr == outputs.end()) {
564 		fprintf(stderr,"<- B_ERROR (no more outputs)\n");
565 		return B_ERROR;
566 	}
567 	// return this output
568 	*out_output = itr->output;
569 	// so next time they won't get the same output again
570 	*cookie = (int32)++itr;
571 	return B_OK;
572 }
573 
574 status_t MediaDemultiplexerNode::DisposeOutputCookie(
575 				int32 cookie)
576 {
577 	fprintf(stderr,"MediaDemultiplexerNode::DisposeOutputCookie\n");
578 	// nothing to do since our cookies are part of the vector iterator
579 	return B_OK;
580 }
581 
582 status_t MediaDemultiplexerNode::SetBufferGroup(
583 				const media_source & for_source,
584 				BBufferGroup * group)
585 {
586 	fprintf(stderr,"MediaDemultiplexerNode::SetBufferGroup\n");
587 	// find the information for this output
588 	vector<MediaOutputInfo>::iterator itr;
589 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
590 		if (itr->output.source == for_source) {
591 			break;
592 		}
593 	}
594 	if (itr == outputs.end()) {
595 		// we don't have that output
596 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
597 		return B_MEDIA_BAD_SOURCE;
598 	}
599 	return itr->SetBufferGroup(group);
600 }
601 
602 	/* Format of clipping is (as int16-s): <from line> <npairs> <startclip> <endclip>. */
603 	/* Repeat for each line where the clipping is different from the previous line. */
604 	/* If <npairs> is negative, use the data from line -<npairs> (there are 0 pairs after */
605 	/* a negative <npairs>. Yes, we only support 32k*32k frame buffers for clipping. */
606 	/* Any non-0 field of 'display' means that that field changed, and if you don't support */
607 	/* that change, you should return an error and ignore the request. Note that the buffer */
608 	/* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */
609 	/* be adhered to. */
610 status_t MediaDemultiplexerNode::VideoClippingChanged(
611 				const media_source & for_source,
612 				int16 num_shorts,
613 				int16 * clip_data,
614 				const media_video_display_info & display,
615 				int32 * _deprecated_)
616 {
617 	return BBufferProducer::VideoClippingChanged(for_source,num_shorts,clip_data,display,_deprecated_);
618 }
619 
620 status_t MediaDemultiplexerNode::GetLatency(
621 				bigtime_t * out_latency)
622 {
623 	fprintf(stderr,"MediaDemultiplexerNode::GetLatency\n");
624 	if (out_latency == 0) {
625 		fprintf(stderr,"<- B_BAD_VALUE\n");
626 		return B_BAD_VALUE;
627 	}
628 	*out_latency = EventLatency() + SchedulingLatency();
629 	return B_OK;
630 }
631 
632 status_t MediaDemultiplexerNode::PrepareToConnect(
633 				const media_source & what,
634 				const media_destination & where,
635 				media_format * format,
636 				media_source * out_source,
637 				char * out_name)
638 {
639 	fprintf(stderr,"MediaDemultiplexerNode::PrepareToConnect\n");
640 	if ((format == 0) || (out_source == 0) || (out_name == 0)) {
641 		fprintf(stderr,"<- B_BAD_VALUE\n");
642 		return B_BAD_VALUE; // no crashes...
643 	}
644 	// find the information for this output
645 	vector<MediaOutputInfo>::iterator itr;
646 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
647 		if (itr->output.source == what) {
648 			break;
649 		}
650 	}
651 	if (itr == outputs.end()) {
652 		// we don't have that output
653 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
654 		return B_MEDIA_BAD_SOURCE;
655 	}
656 	return itr->PrepareToConnect(where,format,out_source,out_name);
657 }
658 
659 void MediaDemultiplexerNode::Connect(
660 				status_t error,
661 				const media_source & source,
662 				const media_destination & destination,
663 				const media_format & format,
664 				char * io_name)
665 {
666 	fprintf(stderr,"MediaDemultiplexerNode::Connect\n");
667 	// find the information for this output
668 	vector<MediaOutputInfo>::iterator itr;
669 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
670 		if (itr->output.source == source) {
671 			break;
672 		}
673 	}
674 	if (itr == outputs.end()) {
675 		// we don't have that output
676 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
677 		return;
678 	}
679 	if (error != B_OK) {
680 		fprintf(stderr,"<- error already\n");
681 		itr->output.destination = media_destination::null;
682 		itr->output.format = itr->generalFormat;
683 		return;
684 	}
685 
686 	// calculate the downstream latency
687 	// must happen before itr->Connect
688 	bigtime_t downstreamLatency;
689 	media_node_id id;
690 	FindLatencyFor(itr->output.destination, &downstreamLatency, &id);
691 
692 	// record the agreed upon values
693 	status_t status;
694 	status = itr->Connect(destination,format,io_name,downstreamLatency);
695 	if (status != B_OK) {
696 		fprintf(stderr,"  itr->Connect returned an error\n");
697 		return;
698 	}
699 
700 	// compute the internal latency
701 	// must happen after itr->Connect
702 	if (fInternalLatency == 0) {
703 		fInternalLatency = 100; // temporary until we finish computing it
704 		ComputeInternalLatency();
705 	}
706 
707 	// If the downstream latency for this output is larger
708 	// than our current downstream latency, we have to increase
709 	// our current downstream latency to be the larger value.
710 	if (downstreamLatency > fDownstreamLatency) {
711 		SetEventLatency(fDownstreamLatency + fInternalLatency);
712 	}
713 
714 	// XXX: what do I set the buffer duration to?
715 	//      it depends on which output is sending!!
716 	// SetBufferDuration(bufferPeriod);
717 
718 	// XXX: do anything else?
719 	return;
720 }
721 
722 void MediaDemultiplexerNode::ComputeInternalLatency() {
723 	fprintf(stderr,"MediaDemultiplexerNode::ComputeInternalLatency\n");
724 //	if (GetCurrentFile() != 0) {
725 //		bigtime_t start, end;
726 //		uint8 * data = new uint8[output.format.u.multistream.max_chunk_size]; // <- buffer group buffer size
727 //		BBuffer * buffer = 0;
728 //		ssize_t bytesRead = 0;
729 //		{ // timed section
730 //			start = TimeSource()->RealTime();
731 //			// first we try to use a real BBuffer
732 //			buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod);
733 //			if (buffer != 0) {
734 //				FillFileBuffer(buffer);
735 //			} else {
736 //				// didn't get a real BBuffer, try simulation by just a read from the disk
737 //				bytesRead = GetCurrentFile()->Read(data,output.format.u.multistream.max_chunk_size);
738 //			}
739 //			end = TimeSource()->RealTime();
740 //		}
741 //		bytesRead = buffer->SizeUsed();
742 //		delete data;
743 //		if (buffer != 0) {
744 //			buffer->Recycle();
745 //		}
746 //		GetCurrentFile()->Seek(-bytesRead,SEEK_CUR); // put it back where we found it
747 //
748 //		fInternalLatency = end - start;
749 //
750 //		fprintf(stderr,"  internal latency from disk read = %lld\n",fInternalLatency);
751 //	} else {
752 		fInternalLatency = 100; // just guess
753 		fprintf(stderr,"  internal latency guessed = %lld\n",fInternalLatency);
754 //	}
755 }
756 
757 void MediaDemultiplexerNode::Disconnect(
758 				const media_source & what,
759 				const media_destination & where)
760 {
761 	fprintf(stderr,"MediaDemultiplexerNode::Disconnect\n");
762 	// find the information for this output
763 	vector<MediaOutputInfo>::iterator itr;
764 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
765 		if (itr->output.source == what) {
766 			break;
767 		}
768 	}
769 	if (itr == outputs.end()) {
770 		// we don't have that output
771 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
772 		return;
773 	}
774 	if (itr->output.destination != where) {
775 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
776 		return;
777 	}
778 	// if this output has an equal (or higher!) latency than
779 	// our current believed downstream latency, we may have to
780 	// update our downstream latency.
781 	bool updateDownstreamLatency = (itr->downstreamLatency >= fDownstreamLatency);
782 	// disconnect this output
783 	itr->Disconnect();
784 	// update the downstream latency if necessary
785 	if (updateDownstreamLatency) {
786 		bigtime_t newDownstreamLatency = 0;
787 		for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
788 			if (itr->downstreamLatency > newDownstreamLatency) {
789 				newDownstreamLatency = itr->downstreamLatency;
790 			}
791 		}
792 		fDownstreamLatency = newDownstreamLatency;
793 	}
794 }
795 
796 void MediaDemultiplexerNode::LateNoticeReceived(
797 				const media_source & what,
798 				bigtime_t how_much,
799 				bigtime_t performance_time)
800 {
801 	fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived\n");
802 	vector<MediaOutputInfo>::iterator itr;
803 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
804 		if (itr->output.source == what) {
805 			break;
806 		}
807 	}
808 	if (itr == outputs.end()) {
809 		// we don't have that output
810 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
811 		return;
812 	}
813 	switch (RunMode()) {
814 		case B_OFFLINE:
815 		    // nothing to do
816 			break;
817 		case B_RECORDING:
818 		    // nothing to do
819 			break;
820 		case B_INCREASE_LATENCY:
821 			fInternalLatency += how_much;
822 			SetEventLatency(fDownstreamLatency + fInternalLatency);
823 			break;
824 		case B_DECREASE_PRECISION:
825 			// XXX: try to catch up by producing buffers faster
826 			break;
827 		case B_DROP_DATA:
828 			// XXX: should we really drop buffers?  just for that output?
829 			break;
830 		default:
831 			// huh?? there aren't any more run modes.
832 			fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived with unexpected run mode.\n");
833 			break;
834 	}
835 }
836 
837 void MediaDemultiplexerNode::EnableOutput(
838 				const media_source & what,
839 				bool enabled,
840 				int32 * _deprecated_)
841 {
842 	fprintf(stderr,"MediaDemultiplexerNode::EnableOutput\n");
843 	// find the information for this output
844 	vector<MediaOutputInfo>::iterator itr;
845 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
846 		if (itr->output.source == what) {
847 			break;
848 		}
849 	}
850 	if (itr == outputs.end()) {
851 		// we don't have that output
852 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
853 		return;
854 	}
855 	status_t status = itr->EnableOutput(enabled);
856 	if (status != B_OK) {
857 		fprintf(stderr,"  error in itr->EnableOutput\n");
858 		return;
859 	}
860 	return;
861 }
862 
863 status_t MediaDemultiplexerNode::SetPlayRate(
864 				int32 numer,
865 				int32 denom)
866 {
867 	BBufferProducer::SetPlayRate(numer,denom); // XXX: do something intelligent later
868 }
869 
870 void MediaDemultiplexerNode::AdditionalBufferRequested(			//	used to be Reserved 0
871 				const media_source & source,
872 				media_buffer_id prev_buffer,
873 				bigtime_t prev_time,
874 				const media_seek_tag * prev_tag)
875 {
876 	fprintf(stderr,"MediaDemultiplexerNode::AdditionalBufferRequested\n");
877 	// find the information for this output
878 	vector<MediaOutputInfo>::iterator itr;
879 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
880 		if (itr->output.source == source) {
881 			break;
882 		}
883 	}
884 	if (itr == outputs.end()) {
885 		// we don't have that output
886 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
887 		return;
888 	}
889 	BBuffer * buffer;
890 	status_t status = itr->AdditionalBufferRequested(prev_buffer,prev_time,prev_tag);
891 	if (status != B_OK) {
892 		fprintf(stderr,"  itr->AdditionalBufferRequested returned an error.\n");
893 		return;
894 	}
895 	return;
896 }
897 
898 void MediaDemultiplexerNode::LatencyChanged(
899 				const media_source & source,
900 				const media_destination & destination,
901 				bigtime_t new_latency,
902 				uint32 flags)
903 {
904 	fprintf(stderr,"MediaDemultiplexerNode::LatencyChanged\n");
905 	// find the information for this output
906 	vector<MediaOutputInfo>::iterator itr;
907 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
908 		if (itr->output.source == source) {
909 			break;
910 		}
911 	}
912 	if (itr == outputs.end()) {
913 		// we don't have that output
914 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
915 		return;
916 	}
917 	if (itr->output.destination != destination) {
918 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
919 		return;
920 	}
921 	fDownstreamLatency = new_latency;
922 	SetEventLatency(fDownstreamLatency + fInternalLatency);
923 	// XXX: we may have to recompute the number of buffers that we are using
924 	// see SetBufferGroup
925 }
926 
927 // -------------------------------------------------------- //
928 // implementation for BMediaEventLooper
929 // -------------------------------------------------------- //
930 
931 void MediaDemultiplexerNode::HandleEvent(
932 				const media_timed_event *event,
933 				bigtime_t lateness,
934 				bool realTimeEvent = false)
935 {
936 	fprintf(stderr,"MediaDemultiplexerNode::HandleEvent\n");
937 	switch (event->type) {
938 		case BTimedEventQueue::B_START:
939 			HandleStart(event,lateness,realTimeEvent);
940 			break;
941 		case BTimedEventQueue::B_SEEK:
942 			HandleSeek(event,lateness,realTimeEvent);
943 			break;
944 		case BTimedEventQueue::B_WARP:
945 			HandleWarp(event,lateness,realTimeEvent);
946 			break;
947 		case BTimedEventQueue::B_STOP:
948 			HandleStop(event,lateness,realTimeEvent);
949 			break;
950 		case BTimedEventQueue::B_HANDLE_BUFFER:
951 			if (RunState() == BMediaEventLooper::B_STARTED) {
952 				HandleBuffer(event,lateness,realTimeEvent);
953 			}
954 			break;
955 		case BTimedEventQueue::B_DATA_STATUS:
956 			HandleDataStatus(event,lateness,realTimeEvent);
957 			break;
958 		case BTimedEventQueue::B_PARAMETER:
959 			HandleParameter(event,lateness,realTimeEvent);
960 			break;
961 		default:
962 			fprintf(stderr,"  unknown event type: %i\n",event->type);
963 			break;
964 	}
965 }
966 
967 /* override to clean up custom events you have added to your queue */
968 void MediaDemultiplexerNode::CleanUpEvent(
969 				const media_timed_event *event)
970 {
971 	BMediaEventLooper::CleanUpEvent(event);
972 }
973 
974 /* called from Offline mode to determine the current time of the node */
975 /* update your internal information whenever it changes */
976 bigtime_t MediaDemultiplexerNode::OfflineTime()
977 {
978 	fprintf(stderr,"MediaDemultiplexerNode::OfflineTime\n");
979 	return BMediaEventLooper::OfflineTime();
980 // XXX: do something else?
981 }
982 
983 /* override only if you know what you are doing! */
984 /* otherwise much badness could occur */
985 /* the actual control loop function: */
986 /* 	waits for messages, Pops events off the queue and calls DispatchEvent */
987 void MediaDemultiplexerNode::ControlLoop() {
988 	BMediaEventLooper::ControlLoop();
989 }
990 
991 // protected:
992 
993 status_t MediaDemultiplexerNode::HandleStart(
994 						const media_timed_event *event,
995 						bigtime_t lateness,
996 						bool realTimeEvent = false)
997 {
998 	fprintf(stderr,"MediaDemultiplexerNode::HandleStart()\n");
999 	if (RunState() != B_STARTED) {
1000 // XXX: Either use the following line or the lines that are not commented.
1001 // There doesn't seem to be a practical difference that i can tell.
1002 //		HandleBuffer(event,lateness,realTimeEvent);
1003 		media_timed_event firstBufferEvent(event->event_time, BTimedEventQueue::B_HANDLE_BUFFER);
1004 		HandleEvent(&firstBufferEvent, 0, false);
1005 		EventQueue()->AddEvent(firstBufferEvent);
1006 	}
1007 	return B_OK;
1008 }
1009 
1010 status_t MediaDemultiplexerNode::HandleSeek(
1011 						const media_timed_event *event,
1012 						bigtime_t lateness,
1013 						bool realTimeEvent = false)
1014 {
1015 	fprintf(stderr,"MediaDemultiplexerNode::HandleSeek(t=%lld,d=%i,bd=%lld)\n",event->event_time,event->data,event->bigdata);
1016 	return B_OK;
1017 }
1018 
1019 status_t MediaDemultiplexerNode::HandleWarp(
1020 						const media_timed_event *event,
1021 						bigtime_t lateness,
1022 						bool realTimeEvent = false)
1023 {
1024 	fprintf(stderr,"MediaDemultiplexerNode::HandleWarp\n");
1025 	return B_OK;
1026 }
1027 
1028 status_t MediaDemultiplexerNode::HandleStop(
1029 						const media_timed_event *event,
1030 						bigtime_t lateness,
1031 						bool realTimeEvent = false)
1032 {
1033 	fprintf(stderr,"MediaDemultiplexerNode::HandleStop\n");
1034 	// flush the queue so downstreamers don't get any more
1035 	EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER);
1036 	return B_OK;
1037 }
1038 
1039 status_t MediaDemultiplexerNode::HandleBuffer(
1040 				const media_timed_event *event,
1041 				bigtime_t lateness,
1042 				bool realTimeEvent = false)
1043 {
1044 	fprintf(stderr,"MediaDemultiplexerNode::HandleBuffer\n");
1045 	BBuffer * buffer = const_cast<BBuffer*>((BBuffer*)event->pointer);
1046 	if (buffer == 0) {
1047 		fprintf(stderr,"<- B_BAD_VALUE\n");
1048 		return B_BAD_VALUE;
1049 	}
1050 	if (buffer->Header()->destination != input.destination.id) {
1051 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
1052 		return B_MEDIA_BAD_DESTINATION;
1053 	}
1054 	if (outputs.begin() == outputs.end()) {
1055 		fprintf(stderr,"<- B_MEDIA_NOT_CONNECTED\n");
1056 		return B_MEDIA_NOT_CONNECTED;
1057 	}
1058 	status_t status = B_OK;
1059 	fprintf(stderr,"  XXX: HandleBuffer not yet implemented.\n");
1060 	// we have to hand the buffer to the extractor
1061 	// and then whenever we get a buffer for an output send it
1062 	// to that particular output (assuming it exists and is enabled)
1063 //	BBuffer * buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod);
1064 //	if (buffer != 0) {
1065 //	    status = FillFileBuffer(buffer);
1066 //	    if (status != B_OK) {
1067 //			fprintf(stderr,"MediaDemultiplexerNode::HandleEvent got an error from FillFileBuffer.\n");
1068 //			buffer->Recycle();
1069 //		} else {
1070 //			if (fOutputEnabled) {
1071 //				status = SendBuffer(buffer,output.destination);
1072 //				if (status != B_OK) {
1073 //					fprintf(stderr,"MediaDemultiplexerNode::HandleEvent got an error from SendBuffer.\n");
1074 //					buffer->Recycle();
1075 //				}
1076 //			} else {
1077 				buffer->Recycle();
1078 //			}
1079 //		}
1080 //	}
1081 	bigtime_t nextEventTime = event->event_time+10000; // fBufferPeriod; // XXX : should multiply
1082 	media_timed_event nextBufferEvent(nextEventTime, BTimedEventQueue::B_HANDLE_BUFFER);
1083 	EventQueue()->AddEvent(nextBufferEvent);
1084 	return status;
1085 }
1086 
1087 status_t MediaDemultiplexerNode::HandleDataStatus(
1088 						const media_timed_event *event,
1089 						bigtime_t lateness,
1090 						bool realTimeEvent = false)
1091 {
1092 	fprintf(stderr,"MediaDemultiplexerNode::HandleDataStatus");
1093 	// find the information for this output
1094 	vector<MediaOutputInfo>::iterator itr;
1095 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
1096 		SendDataStatus(event->data,itr->output.destination,event->event_time);
1097 	}
1098 	return B_OK;
1099 }
1100 
1101 status_t MediaDemultiplexerNode::HandleParameter(
1102 				const media_timed_event *event,
1103 				bigtime_t lateness,
1104 				bool realTimeEvent = false)
1105 {
1106 	fprintf(stderr,"MediaDemultiplexerNode::HandleParameter");
1107 	return B_OK;
1108 }
1109 
1110 // -------------------------------------------------------- //
1111 // MediaDemultiplexerNode specific functions
1112 // -------------------------------------------------------- //
1113 
1114 // public:
1115 
1116 void MediaDemultiplexerNode::GetFlavor(flavor_info * outInfo, int32 id)
1117 {
1118 	fprintf(stderr,"MediaDemultiplexerNode::GetFlavor\n");
1119 	if (outInfo == 0) {
1120 		return;
1121 	}
1122 	outInfo->name = "OpenBeOS Demultiplexer";
1123 	outInfo->info = "A MediaDemultiplexerNode node demultiplexes a multistream into its constituent streams.";
1124 	outInfo->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER;
1125 	outInfo->flavor_flags = B_FLAVOR_IS_LOCAL;
1126 	outInfo->possible_count = INT_MAX;
1127 	outInfo->in_format_count = 1; // 1 input
1128 	media_format * inFormats = new media_format[outInfo->in_format_count];
1129 	GetInputFormat(&inFormats[0]);
1130 	outInfo->in_formats = inFormats;
1131 	outInfo->out_format_count = 1; // 1 output
1132 	media_format * outFormats = new media_format[outInfo->out_format_count];
1133 	GetOutputFormat(&outFormats[0]);
1134 	outInfo->out_formats = outFormats;
1135 	outInfo->internal_id = id;
1136 	return;
1137 }
1138 
1139 void MediaDemultiplexerNode::GetInputFormat(media_format * outFormat)
1140 {
1141 	fprintf(stderr,"MediaDemultiplexerNode::GetInputFormat\n");
1142 	if (outFormat == 0) {
1143 		return;
1144 	}
1145 	outFormat->type = B_MEDIA_MULTISTREAM;
1146 	outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
1147 	outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
1148 	outFormat->u.multistream = media_multistream_format::wildcard;
1149 }
1150 
1151 void MediaDemultiplexerNode::GetOutputFormat(media_format * outFormat)
1152 {
1153 	fprintf(stderr,"MediaDemultiplexerNode::GetOutputFormat\n");
1154 	if (outFormat == 0) {
1155 		return;
1156 	}
1157 	outFormat->type = B_MEDIA_UNKNOWN_TYPE; // more like ANY_TYPE than unknown
1158 	outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
1159 	outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
1160 }
1161 
1162 // protected:
1163 
1164 status_t MediaDemultiplexerNode::AddRequirements(media_format * format)
1165 {
1166 	fprintf(stderr,"MediaDemultiplexerNode::AddRequirements\n");
1167 	return B_OK;
1168 }
1169 
1170 // -------------------------------------------------------- //
1171 // stuffing
1172 // -------------------------------------------------------- //
1173 
1174 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_0(void *) {}
1175 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_1(void *) {}
1176 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_2(void *) {}
1177 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_3(void *) {}
1178 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_4(void *) {}
1179 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_5(void *) {}
1180 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_6(void *) {}
1181 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_7(void *) {}
1182 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_8(void *) {}
1183 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_9(void *) {}
1184 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_10(void *) {}
1185 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_11(void *) {}
1186 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_12(void *) {}
1187 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_13(void *) {}
1188 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_14(void *) {}
1189 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_15(void *) {}
1190