xref: /haiku/src/add-ons/media/media-add-ons/demultiplexer/MediaDemultiplexerNode.cpp (revision 17889a8c70dbb3d59c1412f6431968753c767bab)
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 (input.destination != dest) {
247 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION");
248 		return B_MEDIA_BAD_DESTINATION; // we only have one input so that better be it
249 	}
250 	media_format myFormat;
251 	GetInputFormat(&myFormat);
252 	// Be's format_is_compatible doesn't work,
253 	// so use our format_is_acceptible instead
254 	if (!format_is_acceptible(*format,myFormat)) {
255 		fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n");
256 		return B_MEDIA_BAD_FORMAT;
257 	}
258 	AddRequirements(format);
259 	return B_OK;
260 }
261 
262 status_t MediaDemultiplexerNode::GetNextInput(
263 				int32 * cookie,
264 				media_input * out_input)
265 {
266 	fprintf(stderr,"MediaDemultiplexerNode::GetNextInput\n");
267 	if (*cookie != 0) {
268 		fprintf(stderr,"<- B_ERROR (no more inputs)\n");
269 		return B_ERROR;
270 	}
271 
272 	// so next time they won't get the same input again
273 	*cookie = 1;
274 	*out_input = input;
275 	return B_OK;
276 }
277 
278 void MediaDemultiplexerNode::DisposeInputCookie(
279 				int32 cookie)
280 {
281 	fprintf(stderr,"MediaDemultiplexerNode::DisposeInputCookie\n");
282 	// nothing to do since our cookies are just integers
283 	return; // B_OK;
284 }
285 
286 void MediaDemultiplexerNode::BufferReceived(
287 				BBuffer * buffer)
288 {
289 	fprintf(stderr,"MediaDemultiplexerNode::BufferReceived\n");
290 	switch (buffer->Header()->type) {
291 //		case B_MEDIA_PARAMETERS:
292 //			{
293 //			status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed());
294 //			if (status != B_OK) {
295 //				fprintf(stderr,"ApplyParameterData in MediaDemultiplexerNode::BufferReceived failed\n");
296 //			}
297 //			buffer->Recycle();
298 //			}
299 //			break;
300 		case B_MEDIA_MULTISTREAM:
301 			if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) {
302 				fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in MediaDemultiplexerNode::BufferReceived\n");
303 				// XXX: implement this part
304 				buffer->Recycle();
305 			} else {
306 				media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER,
307 										buffer, BTimedEventQueue::B_RECYCLE_BUFFER);
308 				status_t status = EventQueue()->AddEvent(event);
309 				if (status != B_OK) {
310 					fprintf(stderr,"EventQueue()->AddEvent(event) in MediaDemultiplexerNode::BufferReceived failed\n");
311 					buffer->Recycle();
312 				}
313 			}
314 			break;
315 		default:
316 			fprintf(stderr,"unexpected buffer type in MediaDemultiplexerNode::BufferReceived\n");
317 			buffer->Recycle();
318 			break;
319 	}
320 }
321 
322 void MediaDemultiplexerNode::ProducerDataStatus(
323 				const media_destination & for_whom,
324 				int32 status,
325 				bigtime_t at_performance_time)
326 {
327 	fprintf(stderr,"MediaDemultiplexerNode::ProducerDataStatus\n");
328 	if (input.destination != for_whom) {
329 		fprintf(stderr,"invalid destination received in MediaDemultiplexerNode::ProducerDataStatus\n");
330 		return;
331 	}
332 	media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS,
333 			&input, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL);
334 	EventQueue()->AddEvent(event);
335 }
336 
337 status_t MediaDemultiplexerNode::GetLatencyFor(
338 				const media_destination & for_whom,
339 				bigtime_t * out_latency,
340 				media_node_id * out_timesource)
341 {
342 	fprintf(stderr,"MediaDemultiplexerNode::GetLatencyFor\n");
343 	if ((out_latency == 0) || (out_timesource == 0)) {
344 		fprintf(stderr,"<- B_BAD_VALUE\n");
345 		return B_BAD_VALUE;
346 	}
347 	if (input.destination != for_whom) {
348 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
349 		return B_MEDIA_BAD_DESTINATION;
350 	}
351 	*out_latency = EventLatency();
352 	*out_timesource = TimeSource()->ID();
353 	return B_OK;
354 }
355 
356 status_t MediaDemultiplexerNode::Connected(
357 				const media_source & producer,	/* here's a good place to request buffer group usage */
358 				const media_destination & where,
359 				const media_format & with_format,
360 				media_input * out_input)
361 {
362 	fprintf(stderr,"MediaDemultiplexerNode::Connected\n");
363 	if (input.destination != where) {
364 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
365 		return B_MEDIA_BAD_DESTINATION;
366 	}
367 
368 	// find an appropriate extractor to handle this type
369 	fprintf(stderr,"  XXX: no extractors yet\n");
370 
371 	// initialize the outputs here
372 	// provide all the types that the extractor claims
373 	outputs.empty();
374 
375 	// compute the latency or just guess
376 	fInternalLatency = 500; // just guess
377 	fprintf(stderr,"  internal latency guessed = %lld\n",fInternalLatency);
378 
379 	SetEventLatency(fInternalLatency);
380 
381 	// record the agreed upon values
382 	input.source = producer;
383 	input.format = with_format;
384 	*out_input = input;
385 	return B_OK;
386 }
387 
388 void MediaDemultiplexerNode::Disconnected(
389 				const media_source & producer,
390 				const media_destination & where)
391 {
392 	fprintf(stderr,"MediaDemultiplexerNode::Disconnected\n");
393 	if (input.destination != where) {
394 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
395 		return;
396 	}
397 	if (input.source != producer) {
398 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
399 		return;
400 	}
401 	input.source = media_source::null;
402 	GetInputFormat(&input.format);
403 
404 	outputs.empty();
405 }
406 
407 	/* The notification comes from the upstream producer, so he's already cool with */
408 	/* the format; you should not ask him about it in here. */
409 status_t MediaDemultiplexerNode::FormatChanged(
410 				const media_source & producer,
411 				const media_destination & consumer,
412 				int32 change_tag,
413 				const media_format & format)
414 {
415 	fprintf(stderr,"MediaDemultiplexerNode::FormatChanged\n");
416 	if (input.source != producer) {
417 		return B_MEDIA_BAD_SOURCE;
418 	}
419 	if (input.destination != consumer) {
420 		return B_MEDIA_BAD_DESTINATION;
421 	}
422 	// XXX: implement
423 	fprintf(stderr,"  This is because we asked to have the format changed.\n"
424 	               "  Therefore we must switch to the other extractor that\n"
425 	               "  we presumably have ready.");
426 	input.format = format;
427 	return B_OK;
428 }
429 
430 	/* Given a performance time of some previous buffer, retrieve the remembered tag */
431 	/* of the closest (previous or exact) performance time. Set *out_flags to 0; the */
432 	/* idea being that flags can be added later, and the understood flags returned in */
433 	/* *out_flags. */
434 status_t MediaDemultiplexerNode::SeekTagRequested(
435 				const media_destination & destination,
436 				bigtime_t in_target_time,
437 				uint32 in_flags,
438 				media_seek_tag * out_seek_tag,
439 				bigtime_t * out_tagged_time,
440 				uint32 * out_flags)
441 {
442 	fprintf(stderr,"MediaDemultiplexerNode::SeekTagRequested\n");
443 	// XXX: implement this
444 	return BBufferConsumer::SeekTagRequested(destination,in_target_time,in_flags,
445 											out_seek_tag,out_tagged_time,out_flags);
446 }
447 
448 // -------------------------------------------------------- //
449 // implemention of BBufferProducer
450 // -------------------------------------------------------- //
451 
452 // They are asking us to make the first offering.
453 // So, we get a fresh format and then add requirements
454 status_t MediaDemultiplexerNode::FormatSuggestionRequested(
455 				media_type type,
456 				int32 quality,
457 				media_format * format)
458 {
459 	fprintf(stderr,"MediaDemultiplexerNode::FormatSuggestionRequested\n");
460 	// XXX: how do I pick which stream to supply here?....
461 	//      answer?: get the first compatible stream that is available
462 	fprintf(stderr,"  format suggestion requested not implemented\n");
463 //	if ((type != B_MEDIA_MULTISTREAM) && (type != B_MEDIA_UNKNOWN_TYPE)) {
464 //		fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n");
465 //		return B_MEDIA_BAD_FORMAT;
466 //	}
467 	GetOutputFormat(format);
468 //	AddRequirements(format);
469 
470 	return B_OK;
471 }
472 
473 // They made an offer to us.  We should make sure that the offer is
474 // acceptable, and then we can add any requirements we have on top of
475 // that.  We leave wildcards for anything that we don't care about.
476 status_t MediaDemultiplexerNode::FormatProposal(
477 				const media_source & output_source,
478 				media_format * format)
479 {
480 	fprintf(stderr,"MediaDemultiplexerNode::FormatProposal\n");
481 	// find the information for this output
482 	vector<MediaOutputInfo>::iterator itr;
483 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
484 		if (itr->output.source == output_source) {
485 			break;
486 		}
487 	}
488 	if (itr == outputs.end()) {
489 		// we don't have that output
490 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
491 		return B_MEDIA_BAD_SOURCE;
492 	}
493 	return itr->FormatProposal(format);
494 }
495 
496 // Presumably we have already agreed with them that this format is
497 // okay.  But just in case, we check the offer. (and complain if it
498 // is invalid)  Then as the last thing we do, we get rid of any
499 // remaining wilcards.
500 status_t MediaDemultiplexerNode::FormatChangeRequested(
501 				const media_source & source,
502 				const media_destination & destination,
503 				media_format * io_format,
504 				int32 * _deprecated_)
505 {
506 	fprintf(stderr,"MediaDemultiplexerNode::FormatChangeRequested\n");
507 	// find the information for this output
508 	vector<MediaOutputInfo>::iterator itr;
509 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
510 		if (itr->output.source == source) {
511 			break;
512 		}
513 	}
514 	if (itr == outputs.end()) {
515 		// we don't have that output
516 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
517 		return B_MEDIA_BAD_SOURCE;
518 	}
519 	return itr->FormatChangeRequested(destination,io_format);
520 }
521 
522 status_t MediaDemultiplexerNode::GetNextOutput(	/* cookie starts as 0 */
523 				int32 * cookie,
524 				media_output * out_output)
525 {
526 	fprintf(stderr,"MediaDemultiplexerNode::GetNextOutput\n");
527 	// they want a clean start
528 	if (*cookie == 0) {
529 		*cookie = (int32)outputs.begin();
530 	}
531 	vector<MediaOutputInfo>::iterator itr
532 		= (vector<MediaOutputInfo>::iterator)(*cookie);
533 	// XXX: check here if the vector has been modified.
534 	//      if the iterator is invalid, return an error code??
535 
536 	// they already got our 1 output
537 	if (itr == outputs.end()) {
538 		fprintf(stderr,"<- B_ERROR (no more outputs)\n");
539 		return B_ERROR;
540 	}
541 	// return this output
542 	*out_output = itr->output;
543 	// so next time they won't get the same output again
544 	*cookie = (int32)++itr;
545 	return B_OK;
546 }
547 
548 status_t MediaDemultiplexerNode::DisposeOutputCookie(
549 				int32 cookie)
550 {
551 	fprintf(stderr,"MediaDemultiplexerNode::DisposeOutputCookie\n");
552 	// nothing to do since our cookies are part of the vector iterator
553 	return B_OK;
554 }
555 
556 status_t MediaDemultiplexerNode::SetBufferGroup(
557 				const media_source & for_source,
558 				BBufferGroup * group)
559 {
560 	fprintf(stderr,"MediaDemultiplexerNode::SetBufferGroup\n");
561 	// find the information for this output
562 	vector<MediaOutputInfo>::iterator itr;
563 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
564 		if (itr->output.source == for_source) {
565 			break;
566 		}
567 	}
568 	if (itr == outputs.end()) {
569 		// we don't have that output
570 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
571 		return B_MEDIA_BAD_SOURCE;
572 	}
573 	return itr->SetBufferGroup(group);
574 }
575 
576 	/* Format of clipping is (as int16-s): <from line> <npairs> <startclip> <endclip>. */
577 	/* Repeat for each line where the clipping is different from the previous line. */
578 	/* If <npairs> is negative, use the data from line -<npairs> (there are 0 pairs after */
579 	/* a negative <npairs>. Yes, we only support 32k*32k frame buffers for clipping. */
580 	/* Any non-0 field of 'display' means that that field changed, and if you don't support */
581 	/* that change, you should return an error and ignore the request. Note that the buffer */
582 	/* offset values do not have wildcards; 0 (or -1, or whatever) are real values and must */
583 	/* be adhered to. */
584 status_t MediaDemultiplexerNode::VideoClippingChanged(
585 				const media_source & for_source,
586 				int16 num_shorts,
587 				int16 * clip_data,
588 				const media_video_display_info & display,
589 				int32 * _deprecated_)
590 {
591 	return BBufferProducer::VideoClippingChanged(for_source,num_shorts,clip_data,display,_deprecated_);
592 }
593 
594 status_t MediaDemultiplexerNode::GetLatency(
595 				bigtime_t * out_latency)
596 {
597 	fprintf(stderr,"MediaDemultiplexerNode::GetLatency\n");
598 	if (out_latency == 0) {
599 		fprintf(stderr,"<- B_BAD_VALUE\n");
600 		return B_BAD_VALUE;
601 	}
602 	*out_latency = EventLatency() + SchedulingLatency();
603 	return B_OK;
604 }
605 
606 status_t MediaDemultiplexerNode::PrepareToConnect(
607 				const media_source & what,
608 				const media_destination & where,
609 				media_format * format,
610 				media_source * out_source,
611 				char * out_name)
612 {
613 	fprintf(stderr,"MediaDemultiplexerNode::PrepareToConnect\n");
614 	// find the information for this output
615 	vector<MediaOutputInfo>::iterator itr;
616 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
617 		if (itr->output.source == what) {
618 			break;
619 		}
620 	}
621 	if (itr == outputs.end()) {
622 		// we don't have that output
623 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
624 		return B_MEDIA_BAD_SOURCE;
625 	}
626 	return itr->PrepareToConnect(where,format,out_source,out_name);
627 }
628 
629 void MediaDemultiplexerNode::Connect(
630 				status_t error,
631 				const media_source & source,
632 				const media_destination & destination,
633 				const media_format & format,
634 				char * io_name)
635 {
636 	fprintf(stderr,"MediaDemultiplexerNode::Connect\n");
637 	// find the information for this output
638 	vector<MediaOutputInfo>::iterator itr;
639 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
640 		if (itr->output.source == source) {
641 			break;
642 		}
643 	}
644 	if (itr == outputs.end()) {
645 		// we don't have that output
646 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
647 		return;
648 	}
649 	if (error != B_OK) {
650 		fprintf(stderr,"<- error already\n");
651 		itr->output.destination = media_destination::null;
652 		itr->output.format = itr->generalFormat;
653 		return;
654 	}
655 
656 	// calculate the downstream latency
657 	// must happen before itr->Connect
658 	bigtime_t downstreamLatency;
659 	media_node_id id;
660 	FindLatencyFor(itr->output.destination, &downstreamLatency, &id);
661 
662 	// record the agreed upon values
663 	status_t status;
664 	status = itr->Connect(destination,format,io_name,downstreamLatency);
665 	if (status != B_OK) {
666 		fprintf(stderr,"  itr->Connect returned an error\n");
667 		return;
668 	}
669 
670 	// compute the internal latency
671 	// must happen after itr->Connect
672 	if (fInternalLatency == 0) {
673 		fInternalLatency = 100; // temporary until we finish computing it
674 		ComputeInternalLatency();
675 	}
676 
677 	// If the downstream latency for this output is larger
678 	// than our current downstream latency, we have to increase
679 	// our current downstream latency to be the larger value.
680 	if (downstreamLatency > fDownstreamLatency) {
681 		SetEventLatency(fDownstreamLatency + fInternalLatency);
682 	}
683 
684 	// XXX: what do I set the buffer duration to?
685 	//      it depends on which output is sending!!
686 	// SetBufferDuration(bufferPeriod);
687 
688 	// XXX: do anything else?
689 	return;
690 }
691 
692 void MediaDemultiplexerNode::ComputeInternalLatency() {
693 	fprintf(stderr,"MediaDemultiplexerNode::ComputeInternalLatency\n");
694 //	if (GetCurrentFile() != 0) {
695 //		bigtime_t start, end;
696 //		uint8 * data = new uint8[output.format.u.multistream.max_chunk_size]; // <- buffer group buffer size
697 //		BBuffer * buffer = 0;
698 //		ssize_t bytesRead = 0;
699 //		{ // timed section
700 //			start = TimeSource()->RealTime();
701 //			// first we try to use a real BBuffer
702 //			buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod);
703 //			if (buffer != 0) {
704 //				FillFileBuffer(buffer);
705 //			} else {
706 //				// didn't get a real BBuffer, try simulation by just a read from the disk
707 //				bytesRead = GetCurrentFile()->Read(data,output.format.u.multistream.max_chunk_size);
708 //			}
709 //			end = TimeSource()->RealTime();
710 //		}
711 //		bytesRead = buffer->SizeUsed();
712 //		delete data;
713 //		if (buffer != 0) {
714 //			buffer->Recycle();
715 //		}
716 //		GetCurrentFile()->Seek(-bytesRead,SEEK_CUR); // put it back where we found it
717 //
718 //		fInternalLatency = end - start;
719 //
720 //		fprintf(stderr,"  internal latency from disk read = %lld\n",fInternalLatency);
721 //	} else {
722 		fInternalLatency = 100; // just guess
723 		fprintf(stderr,"  internal latency guessed = %lld\n",fInternalLatency);
724 //	}
725 }
726 
727 void MediaDemultiplexerNode::Disconnect(
728 				const media_source & what,
729 				const media_destination & where)
730 {
731 	fprintf(stderr,"MediaDemultiplexerNode::Disconnect\n");
732 	// find the information for this output
733 	vector<MediaOutputInfo>::iterator itr;
734 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
735 		if (itr->output.source == what) {
736 			break;
737 		}
738 	}
739 	if (itr == outputs.end()) {
740 		// we don't have that output
741 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
742 		return;
743 	}
744 	if (itr->output.destination != where) {
745 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
746 		return;
747 	}
748 	// if this output has an equal (or higher!) latency than
749 	// our current believed downstream latency, we may have to
750 	// update our downstream latency.
751 	bool updateDownstreamLatency = (itr->downstreamLatency >= fDownstreamLatency);
752 	// disconnect this output
753 	itr->Disconnect();
754 	// update the downstream latency if necessary
755 	if (updateDownstreamLatency) {
756 		bigtime_t newDownstreamLatency = 0;
757 		for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
758 			if (itr->downstreamLatency > newDownstreamLatency) {
759 				newDownstreamLatency = itr->downstreamLatency;
760 			}
761 		}
762 		fDownstreamLatency = newDownstreamLatency;
763 	}
764 }
765 
766 void MediaDemultiplexerNode::LateNoticeReceived(
767 				const media_source & what,
768 				bigtime_t how_much,
769 				bigtime_t performance_time)
770 {
771 	fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived\n");
772 	vector<MediaOutputInfo>::iterator itr;
773 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
774 		if (itr->output.source == what) {
775 			break;
776 		}
777 	}
778 	if (itr == outputs.end()) {
779 		// we don't have that output
780 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
781 		return;
782 	}
783 	switch (RunMode()) {
784 		case B_OFFLINE:
785 		    // nothing to do
786 			break;
787 		case B_RECORDING:
788 		    // nothing to do
789 			break;
790 		case B_INCREASE_LATENCY:
791 			fInternalLatency += how_much;
792 			SetEventLatency(fDownstreamLatency + fInternalLatency);
793 			break;
794 		case B_DECREASE_PRECISION:
795 			// XXX: try to catch up by producing buffers faster
796 			break;
797 		case B_DROP_DATA:
798 			// XXX: should we really drop buffers?  just for that output?
799 			break;
800 		default:
801 			// huh?? there aren't any more run modes.
802 			fprintf(stderr,"MediaDemultiplexerNode::LateNoticeReceived with unexpected run mode.\n");
803 			break;
804 	}
805 }
806 
807 void MediaDemultiplexerNode::EnableOutput(
808 				const media_source & what,
809 				bool enabled,
810 				int32 * _deprecated_)
811 {
812 	fprintf(stderr,"MediaDemultiplexerNode::EnableOutput\n");
813 	// find the information for this output
814 	vector<MediaOutputInfo>::iterator itr;
815 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
816 		if (itr->output.source == what) {
817 			break;
818 		}
819 	}
820 	if (itr == outputs.end()) {
821 		// we don't have that output
822 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
823 		return;
824 	}
825 	status_t status = itr->EnableOutput(enabled);
826 	if (status != B_OK) {
827 		fprintf(stderr,"  error in itr->EnableOutput\n");
828 		return;
829 	}
830 	return;
831 }
832 
833 status_t MediaDemultiplexerNode::SetPlayRate(
834 				int32 numer,
835 				int32 denom)
836 {
837 	BBufferProducer::SetPlayRate(numer,denom); // XXX: do something intelligent later
838 }
839 
840 void MediaDemultiplexerNode::AdditionalBufferRequested(			//	used to be Reserved 0
841 				const media_source & source,
842 				media_buffer_id prev_buffer,
843 				bigtime_t prev_time,
844 				const media_seek_tag * prev_tag)
845 {
846 	fprintf(stderr,"MediaDemultiplexerNode::AdditionalBufferRequested\n");
847 	// find the information for this output
848 	vector<MediaOutputInfo>::iterator itr;
849 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
850 		if (itr->output.source == source) {
851 			break;
852 		}
853 	}
854 	if (itr == outputs.end()) {
855 		// we don't have that output
856 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
857 		return;
858 	}
859 	BBuffer * buffer;
860 	status_t status = itr->AdditionalBufferRequested(prev_buffer,prev_time,prev_tag);
861 	if (status != B_OK) {
862 		fprintf(stderr,"  itr->AdditionalBufferRequested returned an error.\n");
863 		return;
864 	}
865 	return;
866 }
867 
868 void MediaDemultiplexerNode::LatencyChanged(
869 				const media_source & source,
870 				const media_destination & destination,
871 				bigtime_t new_latency,
872 				uint32 flags)
873 {
874 	fprintf(stderr,"MediaDemultiplexerNode::LatencyChanged\n");
875 	// find the information for this output
876 	vector<MediaOutputInfo>::iterator itr;
877 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
878 		if (itr->output.source == source) {
879 			break;
880 		}
881 	}
882 	if (itr == outputs.end()) {
883 		// we don't have that output
884 		fprintf(stderr,"<- B_MEDIA_BAD_SOURCE\n");
885 		return;
886 	}
887 	if (itr->output.destination != destination) {
888 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
889 		return;
890 	}
891 	fDownstreamLatency = new_latency;
892 	SetEventLatency(fDownstreamLatency + fInternalLatency);
893 	// XXX: we may have to recompute the number of buffers that we are using
894 	// see SetBufferGroup
895 }
896 
897 // -------------------------------------------------------- //
898 // implementation for BMediaEventLooper
899 // -------------------------------------------------------- //
900 
901 void MediaDemultiplexerNode::HandleEvent(
902 				const media_timed_event *event,
903 				bigtime_t lateness,
904 				bool realTimeEvent = false)
905 {
906 	fprintf(stderr,"MediaDemultiplexerNode::HandleEvent\n");
907 	switch (event->type) {
908 		case BTimedEventQueue::B_START:
909 			HandleStart(event,lateness,realTimeEvent);
910 			break;
911 		case BTimedEventQueue::B_SEEK:
912 			HandleSeek(event,lateness,realTimeEvent);
913 			break;
914 		case BTimedEventQueue::B_WARP:
915 			HandleWarp(event,lateness,realTimeEvent);
916 			break;
917 		case BTimedEventQueue::B_STOP:
918 			HandleStop(event,lateness,realTimeEvent);
919 			break;
920 		case BTimedEventQueue::B_HANDLE_BUFFER:
921 			if (RunState() == BMediaEventLooper::B_STARTED) {
922 				HandleBuffer(event,lateness,realTimeEvent);
923 			}
924 			break;
925 		case BTimedEventQueue::B_DATA_STATUS:
926 			HandleDataStatus(event,lateness,realTimeEvent);
927 			break;
928 		case BTimedEventQueue::B_PARAMETER:
929 			HandleParameter(event,lateness,realTimeEvent);
930 			break;
931 		default:
932 			fprintf(stderr,"  unknown event type: %i\n",event->type);
933 			break;
934 	}
935 }
936 
937 /* override to clean up custom events you have added to your queue */
938 void MediaDemultiplexerNode::CleanUpEvent(
939 				const media_timed_event *event)
940 {
941 	BMediaEventLooper::CleanUpEvent(event);
942 }
943 
944 /* called from Offline mode to determine the current time of the node */
945 /* update your internal information whenever it changes */
946 bigtime_t MediaDemultiplexerNode::OfflineTime()
947 {
948 	fprintf(stderr,"MediaDemultiplexerNode::OfflineTime\n");
949 	return BMediaEventLooper::OfflineTime();
950 // XXX: do something else?
951 }
952 
953 /* override only if you know what you are doing! */
954 /* otherwise much badness could occur */
955 /* the actual control loop function: */
956 /* 	waits for messages, Pops events off the queue and calls DispatchEvent */
957 void MediaDemultiplexerNode::ControlLoop() {
958 	BMediaEventLooper::ControlLoop();
959 }
960 
961 // protected:
962 
963 status_t MediaDemultiplexerNode::HandleStart(
964 						const media_timed_event *event,
965 						bigtime_t lateness,
966 						bool realTimeEvent = false)
967 {
968 	fprintf(stderr,"MediaDemultiplexerNode::HandleStart()\n");
969 	if (RunState() != B_STARTED) {
970 // XXX: Either use the following line or the lines that are not commented.
971 // There doesn't seem to be a practical difference that i can tell.
972 //		HandleBuffer(event,lateness,realTimeEvent);
973 		media_timed_event firstBufferEvent(event->event_time, BTimedEventQueue::B_HANDLE_BUFFER);
974 		HandleEvent(&firstBufferEvent, 0, false);
975 		EventQueue()->AddEvent(firstBufferEvent);
976 	}
977 	return B_OK;
978 }
979 
980 status_t MediaDemultiplexerNode::HandleSeek(
981 						const media_timed_event *event,
982 						bigtime_t lateness,
983 						bool realTimeEvent = false)
984 {
985 	fprintf(stderr,"MediaDemultiplexerNode::HandleSeek(t=%lld,d=%i,bd=%lld)\n",event->event_time,event->data,event->bigdata);
986 	return B_OK;
987 }
988 
989 status_t MediaDemultiplexerNode::HandleWarp(
990 						const media_timed_event *event,
991 						bigtime_t lateness,
992 						bool realTimeEvent = false)
993 {
994 	fprintf(stderr,"MediaDemultiplexerNode::HandleWarp\n");
995 	return B_OK;
996 }
997 
998 status_t MediaDemultiplexerNode::HandleStop(
999 						const media_timed_event *event,
1000 						bigtime_t lateness,
1001 						bool realTimeEvent = false)
1002 {
1003 	fprintf(stderr,"MediaDemultiplexerNode::HandleStop\n");
1004 	// flush the queue so downstreamers don't get any more
1005 	EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, BTimedEventQueue::B_HANDLE_BUFFER);
1006 	return B_OK;
1007 }
1008 
1009 status_t MediaDemultiplexerNode::HandleBuffer(
1010 				const media_timed_event *event,
1011 				bigtime_t lateness,
1012 				bool realTimeEvent = false)
1013 {
1014 	fprintf(stderr,"MediaDemultiplexerNode::HandleBuffer\n");
1015 	BBuffer * buffer = const_cast<BBuffer*>((BBuffer*)event->pointer);
1016 	if (buffer == 0) {
1017 		fprintf(stderr,"<- B_BAD_VALUE\n");
1018 		return B_BAD_VALUE;
1019 	}
1020 	if (buffer->Header()->destination != input.destination.id) {
1021 		fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n");
1022 		return B_MEDIA_BAD_DESTINATION;
1023 	}
1024 	if (outputs.begin() == outputs.end()) {
1025 		fprintf(stderr,"<- B_MEDIA_NOT_CONNECTED\n");
1026 		return B_MEDIA_NOT_CONNECTED;
1027 	}
1028 	status_t status = B_OK;
1029 	fprintf(stderr,"  XXX: HandleBuffer not yet implemented.\n");
1030 	// we have to hand the buffer to the extractor
1031 	// and then whenever we get a buffer for an output send it
1032 	// to that particular output (assuming it exists and is enabled)
1033 //	BBuffer * buffer = fBufferGroup->RequestBuffer(output.format.u.multistream.max_chunk_size,fBufferPeriod);
1034 //	if (buffer != 0) {
1035 //	    status = FillFileBuffer(buffer);
1036 //	    if (status != B_OK) {
1037 //			fprintf(stderr,"MediaDemultiplexerNode::HandleEvent got an error from FillFileBuffer.\n");
1038 //			buffer->Recycle();
1039 //		} else {
1040 //			if (fOutputEnabled) {
1041 //				status = SendBuffer(buffer,output.destination);
1042 //				if (status != B_OK) {
1043 //					fprintf(stderr,"MediaDemultiplexerNode::HandleEvent got an error from SendBuffer.\n");
1044 //					buffer->Recycle();
1045 //				}
1046 //			} else {
1047 				buffer->Recycle();
1048 //			}
1049 //		}
1050 //	}
1051 	bigtime_t nextEventTime = event->event_time+10000; // fBufferPeriod; // XXX : should multiply
1052 	media_timed_event nextBufferEvent(nextEventTime, BTimedEventQueue::B_HANDLE_BUFFER);
1053 	EventQueue()->AddEvent(nextBufferEvent);
1054 	return status;
1055 }
1056 
1057 status_t MediaDemultiplexerNode::HandleDataStatus(
1058 						const media_timed_event *event,
1059 						bigtime_t lateness,
1060 						bool realTimeEvent = false)
1061 {
1062 	fprintf(stderr,"MediaDemultiplexerNode::HandleDataStatus");
1063 	// find the information for this output
1064 	vector<MediaOutputInfo>::iterator itr;
1065 	for(itr = outputs.begin() ; (itr != outputs.end()) ; itr++) {
1066 		SendDataStatus(event->data,itr->output.destination,event->event_time);
1067 	}
1068 	return B_OK;
1069 }
1070 
1071 status_t MediaDemultiplexerNode::HandleParameter(
1072 				const media_timed_event *event,
1073 				bigtime_t lateness,
1074 				bool realTimeEvent = false)
1075 {
1076 	fprintf(stderr,"MediaDemultiplexerNode::HandleParameter");
1077 	return B_OK;
1078 }
1079 
1080 // -------------------------------------------------------- //
1081 // MediaDemultiplexerNode specific functions
1082 // -------------------------------------------------------- //
1083 
1084 // public:
1085 
1086 void MediaDemultiplexerNode::GetFlavor(flavor_info * outInfo, int32 id)
1087 {
1088 	fprintf(stderr,"MediaDemultiplexerNode::GetFlavor\n");
1089 	if (outInfo == 0) {
1090 		return;
1091 	}
1092 	outInfo->name = "Haiku Demultiplexer";
1093 	outInfo->info = "A MediaDemultiplexerNode node demultiplexes a multistream into its constituent streams.";
1094 	outInfo->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER;
1095 	outInfo->flavor_flags = B_FLAVOR_IS_LOCAL;
1096 	outInfo->possible_count = INT_MAX;
1097 	outInfo->in_format_count = 1; // 1 input
1098 	media_format * inFormats = new media_format[outInfo->in_format_count];
1099 	GetInputFormat(&inFormats[0]);
1100 	outInfo->in_formats = inFormats;
1101 	outInfo->out_format_count = 1; // 1 output
1102 	media_format * outFormats = new media_format[outInfo->out_format_count];
1103 	GetOutputFormat(&outFormats[0]);
1104 	outInfo->out_formats = outFormats;
1105 	outInfo->internal_id = id;
1106 	return;
1107 }
1108 
1109 void MediaDemultiplexerNode::GetInputFormat(media_format * outFormat)
1110 {
1111 	fprintf(stderr,"MediaDemultiplexerNode::GetInputFormat\n");
1112 	if (outFormat == 0) {
1113 		return;
1114 	}
1115 	outFormat->type = B_MEDIA_MULTISTREAM;
1116 	outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
1117 	outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
1118 	outFormat->u.multistream = media_multistream_format::wildcard;
1119 }
1120 
1121 void MediaDemultiplexerNode::GetOutputFormat(media_format * outFormat)
1122 {
1123 	fprintf(stderr,"MediaDemultiplexerNode::GetOutputFormat\n");
1124 	if (outFormat == 0) {
1125 		return;
1126 	}
1127 	outFormat->type = B_MEDIA_UNKNOWN_TYPE; // more like ANY_TYPE than unknown
1128 	outFormat->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
1129 	outFormat->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS;
1130 }
1131 
1132 // protected:
1133 
1134 status_t MediaDemultiplexerNode::AddRequirements(media_format * format)
1135 {
1136 	fprintf(stderr,"MediaDemultiplexerNode::AddRequirements\n");
1137 	return B_OK;
1138 }
1139 
1140 // -------------------------------------------------------- //
1141 // stuffing
1142 // -------------------------------------------------------- //
1143 
1144 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_0(void *) {}
1145 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_1(void *) {}
1146 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_2(void *) {}
1147 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_3(void *) {}
1148 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_4(void *) {}
1149 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_5(void *) {}
1150 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_6(void *) {}
1151 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_7(void *) {}
1152 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_8(void *) {}
1153 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_9(void *) {}
1154 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_10(void *) {}
1155 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_11(void *) {}
1156 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_12(void *) {}
1157 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_13(void *) {}
1158 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_14(void *) {}
1159 status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_15(void *) {}
1160