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
32MediaDemultiplexerNode::~MediaDemultiplexerNode(void)
33{
34	fprintf(stderr,"MediaDemultiplexerNode::~MediaDemultiplexerNode\n");
35	// Stop the BMediaEventLooper thread
36	Quit();
37}
38
39MediaDemultiplexerNode::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
71status_t MediaDemultiplexerNode::InitCheck(void) const
72{
73	fprintf(stderr,"MediaDemultiplexerNode::InitCheck\n");
74	return fInitCheckStatus;
75}
76
77status_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
88BMediaAddOn * 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
102void 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
109void 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
121void 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
129void MediaDemultiplexerNode::SetRunMode(
130				run_mode mode)
131{
132	fprintf(stderr,"MediaDemultiplexerNode::SetRunMode(%i)\n",mode);
133	BMediaEventLooper::SetRunMode(mode);
134}
135
136void 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
144void MediaDemultiplexerNode::Preroll(void)
145{
146	fprintf(stderr,"MediaDemultiplexerNode::Preroll\n");
147	// XXX:Performance opportunity
148	BMediaNode::Preroll();
149}
150
151void MediaDemultiplexerNode::SetTimeSource(
152				BTimeSource * time_source)
153{
154	fprintf(stderr,"MediaDemultiplexerNode::SetTimeSource\n");
155	BMediaNode::SetTimeSource(time_source);
156}
157
158status_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
187status_t MediaDemultiplexerNode::RequestCompleted(
188				const media_request_info & info)
189{
190	fprintf(stderr,"MediaDemultiplexerNode::RequestCompleted\n");
191	return BMediaNode::RequestCompleted(info);
192}
193
194status_t MediaDemultiplexerNode::DeleteHook(
195				BMediaNode * node)
196{
197	fprintf(stderr,"MediaDemultiplexerNode::DeleteHook\n");
198	return BMediaEventLooper::DeleteHook(node);
199}
200
201void 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
219status_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
227status_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.
241status_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
262status_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
278void 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
286void 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
322void 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
337status_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
356status_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
388void 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. */
409status_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. */
434status_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
454status_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.
476status_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.
500status_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
522status_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
548status_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
556status_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. */
584status_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
594status_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
606status_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
629void 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
692void 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
727void 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
766void 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
807void 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
833status_t MediaDemultiplexerNode::SetPlayRate(
834				int32 numer,
835				int32 denom)
836{
837	BBufferProducer::SetPlayRate(numer,denom); // XXX: do something intelligent later
838}
839
840void 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
868void 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
901void 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 */
938void 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 */
946bigtime_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 */
957void MediaDemultiplexerNode::ControlLoop() {
958	BMediaEventLooper::ControlLoop();
959}
960
961// protected:
962
963status_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
980status_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
989status_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
998status_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
1009status_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
1057status_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
1071status_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
1086void 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
1109void 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
1121void 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
1134status_t MediaDemultiplexerNode::AddRequirements(media_format * format)
1135{
1136	fprintf(stderr,"MediaDemultiplexerNode::AddRequirements\n");
1137	return B_OK;
1138}
1139
1140// -------------------------------------------------------- //
1141// stuffing
1142// -------------------------------------------------------- //
1143
1144status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_0(void *) {}
1145status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_1(void *) {}
1146status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_2(void *) {}
1147status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_3(void *) {}
1148status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_4(void *) {}
1149status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_5(void *) {}
1150status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_6(void *) {}
1151status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_7(void *) {}
1152status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_8(void *) {}
1153status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_9(void *) {}
1154status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_10(void *) {}
1155status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_11(void *) {}
1156status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_12(void *) {}
1157status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_13(void *) {}
1158status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_14(void *) {}
1159status_t MediaDemultiplexerNode::_Reserved_MediaDemultiplexerNode_15(void *) {}
1160