xref: /haiku/src/apps/cortex/addons/common/AudioFilterNode.cpp (revision 425ac1b60a56f4df7a0e88bd784545c0ec4fa01f)
1 /*
2  * Copyright (c) 1999-2000, Eric Moon.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions, and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions, and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 
32 // AudioFilterNode.cpp
33 
34 #include "AudioFilterNode.h"
35 
36 #include "AudioBuffer.h"
37 #include "IParameterSet.h"
38 #include "IAudioOpFactory.h"
39 #include "IAudioOp.h"
40 #include "SoundUtils.h"
41 
42 #include <Buffer.h>
43 #include <BufferGroup.h>
44 #include <ByteOrder.h>
45 #include <Catalog.h>
46 #include <ParameterWeb.h>
47 #include <String.h>
48 #include <TimeSource.h>
49 
50 
51 #include <cstdio>
52 #include <cstdlib>
53 #include <cstring>
54 //#include <cmath>
55 
56 #undef B_TRANSLATION_CONTEXT
57 #define B_TRANSLATION_CONTEXT "CortexAddOnsCommon"
58 
59 // -------------------------------------------------------- //
60 // constants
61 // -------------------------------------------------------- //
62 
63 // input-ID symbols
64 enum input_id_t {
65 	ID_AUDIO_INPUT
66 };
67 
68 // output-ID symbols
69 enum output_id_t {
70 	ID_AUDIO_MIX_OUTPUT
71 	//ID_AUDIO_WET_OUTPUT ...
72 };
73 
74 // -------------------------------------------------------- //
75 // *** HOOKS
76 // -------------------------------------------------------- //
77 
78 // *** FORMAT NEGOTIATION
79 
80 // requests the required format for the given type (ioFormat.type must be
81 // filled in!)
82 // upon returning, all fields must be filled in.
83 // Default:
84 // - raw_audio format:
85 //   float
86 //   44100hz
87 //   host-endian
88 //   1 channel
89 //   1k buffers
90 
getPreferredInputFormat(media_format & ioFormat)91 status_t AudioFilterNode::getPreferredInputFormat(
92 	media_format&								ioFormat) {
93 	return getPreferredOutputFormat(ioFormat);
94 }
95 
getPreferredOutputFormat(media_format & ioFormat)96 status_t AudioFilterNode::getPreferredOutputFormat(
97 	media_format&								ioFormat) {
98 
99 	if(ioFormat.type != B_MEDIA_RAW_AUDIO)
100 		return B_MEDIA_BAD_FORMAT;
101 
102 	media_raw_audio_format& f = ioFormat.u.raw_audio;
103 	f.format = media_raw_audio_format::B_AUDIO_FLOAT;
104 	f.frame_rate = 44100.0;
105 	f.channel_count = 1;
106 	f.byte_order = B_MEDIA_HOST_ENDIAN; //(B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
107 	f.buffer_size = 1024;
108 
109 	return B_OK;
110 }
111 
112 // test the given template format against a proposed format.
113 // specialize wildcards for fields where the template contains
114 // non-wildcard data; write required fields into proposed format
115 // if they mismatch.
116 // Returns B_OK if the proposed format doesn't conflict with the
117 // template, or B_MEDIA_BAD_FORMAT otherwise.
118 
_validate_raw_audio_format(const media_format & preferredFormat,media_format & ioProposedFormat)119 status_t AudioFilterNode::_validate_raw_audio_format(
120 	const media_format&					preferredFormat,
121 	media_format&								ioProposedFormat) {
122 
123 	char formatStr[256];
124 	PRINT(("AudioFilterNode::_validate_raw_audio_format()\n"));
125 
126 	ASSERT(preferredFormat.type == B_MEDIA_RAW_AUDIO);
127 
128 	string_for_format(preferredFormat, formatStr, 255);
129 	PRINT(("\ttemplate format: %s\n", formatStr));
130 
131 	string_for_format(ioProposedFormat, formatStr, 255);
132 	PRINT(("\tincoming proposed format: %s\n", formatStr));
133 
134 	if (ioProposedFormat.type != B_MEDIA_RAW_AUDIO) {
135 		// out of the ballpark
136 		ioProposedFormat = preferredFormat;
137 		return B_MEDIA_BAD_FORMAT;
138 	}
139 
140 	if (!format_is_compatible(preferredFormat, ioProposedFormat)) {
141 		string_for_format(ioProposedFormat, formatStr, 255);
142 		PRINT((
143 			"\tformat conflict; suggesting:\n\tformat %s\n", formatStr));
144 		return B_MEDIA_BAD_FORMAT;
145 	}
146 
147 	ioProposedFormat.SpecializeTo(&preferredFormat);
148 
149 	string_for_format(ioProposedFormat, formatStr, 255);
150 	PRINT(("\toutbound proposed format: %s\n", formatStr));
151 
152 	return B_OK;
153 }
154 
validateProposedInputFormat(const media_format & preferredFormat,media_format & ioProposedFormat)155 status_t AudioFilterNode::validateProposedInputFormat(
156 	const media_format&					preferredFormat,
157 	media_format&								ioProposedFormat) {
158 
159 	return _validate_raw_audio_format(
160 		preferredFormat, ioProposedFormat);
161 }
162 
validateProposedOutputFormat(const media_format & preferredFormat,media_format & ioProposedFormat)163 status_t AudioFilterNode::validateProposedOutputFormat(
164 	const media_format&					preferredFormat,
165 	media_format&								ioProposedFormat) {
166 
167 	return _validate_raw_audio_format(
168 		preferredFormat, ioProposedFormat);
169 }
170 
171 
_specialize_raw_audio_format(const media_format & templateFormat,media_format & ioFormat)172 void AudioFilterNode::_specialize_raw_audio_format(
173 	const media_format&					templateFormat,
174 	media_format&								ioFormat) {
175 
176 	ASSERT(templateFormat.type == B_MEDIA_RAW_AUDIO);
177 	ASSERT(ioFormat.type == B_MEDIA_RAW_AUDIO);
178 
179 	media_raw_audio_format& f = ioFormat.u.raw_audio;
180 	const media_raw_audio_format& p = templateFormat.u.raw_audio;
181 	const media_raw_audio_format& w = media_raw_audio_format::wildcard;
182 
183 	if(f.format == w.format) {
184 		ASSERT(p.format);
185 		f.format = p.format;
186 	}
187 
188 	if(f.channel_count == w.channel_count) {
189 		ASSERT(p.channel_count);
190 		f.channel_count = p.channel_count;
191 	}
192 
193 	if(f.frame_rate == w.frame_rate) {
194 		ASSERT(p.frame_rate);
195 		f.frame_rate = p.frame_rate;
196 	}
197 
198 	if(f.byte_order == w.byte_order) {
199 		ASSERT(p.byte_order);
200 		f.byte_order = p.byte_order;
201 	}
202 
203 	if(f.buffer_size == w.buffer_size) {
204 		ASSERT(p.buffer_size);
205 		f.buffer_size = p.buffer_size;
206 	}
207 }
208 
209 // -------------------------------------------------------- //
210 // *** ctor/dtor
211 // -------------------------------------------------------- //
212 
~AudioFilterNode()213 AudioFilterNode::~AudioFilterNode() {
214 	// shut down
215 	Quit();
216 
217 	// clean up
218 	if(m_parameterSet) delete m_parameterSet;
219 	if(m_opFactory) delete m_opFactory;
220 	if(m_op) delete m_op;
221 }
222 
223 // the node acquires ownership of opFactory and
AudioFilterNode(const char * name,IAudioOpFactory * opFactory,BMediaAddOn * addOn)224 AudioFilterNode::AudioFilterNode(
225 	const char*									name,
226 	IAudioOpFactory*						opFactory,
227 	BMediaAddOn*								addOn) :
228 
229 	// * init base classes
230 	BMediaNode(name), // (virtual base)
231 	BBufferConsumer(B_MEDIA_RAW_AUDIO),
232 	BBufferProducer(B_MEDIA_RAW_AUDIO),
233 	BControllable(),
234 	BMediaEventLooper(),
235 
236 	// * init connection state
237 	m_outputEnabled(true),
238 	m_downstreamLatency(0),
239 	m_processingLatency(0),
240 	m_bufferGroup(0),
241 
242 	// * init parameter/operation components
243 	m_parameterSet(opFactory->createParameterSet()),
244 	m_opFactory(opFactory),
245 	m_op(0),
246 
247 	// * init add-on if any
248 	m_addOn(addOn) {
249 
250 	ASSERT(m_opFactory);
251 	ASSERT(m_parameterSet);
252 
253 	PRINT((
254 		"AudioFilterNode::AudioFilterNode()\n"));
255 
256 	// the rest of the initialization happens in NodeRegistered().
257 }
258 
259 // -------------------------------------------------------- //
260 // *** BMediaNode
261 // -------------------------------------------------------- //
262 
HandleMessage(int32 code,const void * data,size_t size)263 status_t AudioFilterNode::HandleMessage(
264 	int32												code,
265 	const void*									data,
266 	size_t											size) {
267 
268 	// pass off to each base class
269 	if(
270 		BBufferConsumer::HandleMessage(code, data, size) &&
271 		BBufferProducer::HandleMessage(code, data, size) &&
272 		BControllable::HandleMessage(code, data, size) &&
273 		BMediaNode::HandleMessage(code, data, size))
274 		BMediaNode::HandleBadMessage(code, data, size);
275 
276 	// +++++ return error on bad message?
277 	return B_OK;
278 }
279 
AddOn(int32 * outID) const280 BMediaAddOn* AudioFilterNode::AddOn(
281 	int32*											outID) const {
282 
283 	if(m_addOn)
284 		*outID = 0;
285 	return m_addOn;
286 }
287 
SetRunMode(run_mode mode)288 void AudioFilterNode::SetRunMode(
289 	run_mode										mode) {
290 
291 	// disallow offline mode for now
292 	// +++++
293 	if(mode == B_OFFLINE)
294 		ReportError(B_NODE_FAILED_SET_RUN_MODE);
295 
296 	// +++++ any other work to do?
297 
298 	// hand off
299 	BMediaEventLooper::SetRunMode(mode);
300 }
301 
302 // -------------------------------------------------------- //
303 // *** BMediaEventLooper
304 // -------------------------------------------------------- //
305 
HandleEvent(const media_timed_event * event,bigtime_t howLate,bool realTimeEvent)306 void AudioFilterNode::HandleEvent(
307 	const media_timed_event*		event,
308 	bigtime_t										howLate,
309 	bool												realTimeEvent) {
310 
311 	ASSERT(event);
312 
313 	switch(event->type) {
314 		case BTimedEventQueue::B_PARAMETER:
315 			handleParameterEvent(event);
316 			break;
317 
318 		case BTimedEventQueue::B_START:
319 			handleStartEvent(event);
320 			break;
321 
322 		case BTimedEventQueue::B_STOP:
323 			handleStopEvent(event);
324 			break;
325 
326 		default:
327 			ignoreEvent(event);
328 			break;
329 	}
330 }
331 
332 // "The Media Server calls this hook function after the node has
333 //  been registered.  This is derived from BMediaNode; BMediaEventLooper
334 //  implements it to call Run() automatically when the node is registered;
335 //  if you implement NodeRegistered() you should call through to
336 //  BMediaEventLooper::NodeRegistered() after you've done your custom
337 //  operations."
338 
NodeRegistered()339 void AudioFilterNode::NodeRegistered() {
340 
341 	PRINT(("AudioFilterNode::NodeRegistered()\n"));
342 	status_t err;
343 
344 	// init input
345 	m_input.destination.port = ControlPort();
346 	m_input.destination.id = ID_AUDIO_INPUT;
347 	m_input.node = Node();
348 	m_input.source = media_source::null;
349 
350 	m_input.format.type = B_MEDIA_RAW_AUDIO;
351 	err = getRequiredInputFormat(m_input.format);
352 	ASSERT(err == B_OK);
353 
354 	strlcpy(m_input.name, B_TRANSLATE("Audio input"), B_MEDIA_NAME_LENGTH);
355 
356 	// init output
357 	m_output.source.port = ControlPort();
358 	m_output.source.id = ID_AUDIO_MIX_OUTPUT;
359 	m_output.node = Node();
360 	m_output.destination = media_destination::null;
361 
362 	m_output.format.type = B_MEDIA_RAW_AUDIO;
363 	err = getRequiredOutputFormat(m_output.format);
364 	ASSERT(err == B_OK);
365 
366 	strlcpy(m_output.name, B_TRANSLATE("Audio output"), B_MEDIA_NAME_LENGTH);
367 
368 	// init parameters
369 	initParameterWeb();
370 
371 	// Start the BMediaEventLooper thread
372 	SetPriority(B_REAL_TIME_PRIORITY);
373 	Run();
374 }
375 
376 // "Augment OfflineTime() to compute the node's current time; it's called
377 //  by the Media Kit when it's in offline mode. Update any appropriate
378 //  internal information as well, then call through to the BMediaEventLooper
379 //  implementation."
380 
OfflineTime()381 bigtime_t AudioFilterNode::OfflineTime() {
382 	// +++++ offline mode not implemented +++++
383 	return 0LL;
384 }
385 
386 
387 // -------------------------------------------------------- //
388 // *** BBufferConsumer
389 // -------------------------------------------------------- //
390 
AcceptFormat(const media_destination & destination,media_format * ioFormat)391 status_t AudioFilterNode::AcceptFormat(
392 	const media_destination&		destination,
393 	media_format*								ioFormat) {
394 
395 	PRINT(("AudioFilterNode::AcceptFormat()\n"));
396 	status_t err;
397 
398 	// sanity checks
399 	if(destination != m_input.destination) {
400 		PRINT(("\tbad destination\n"));
401 		return B_MEDIA_BAD_DESTINATION;
402 	}
403 	if(ioFormat->type != B_MEDIA_RAW_AUDIO) {
404 		PRINT(("\tnot B_MEDIA_RAW_AUDIO\n"));
405 		return B_MEDIA_BAD_FORMAT;
406 	}
407 
408 	media_format required;
409 	required.type = B_MEDIA_RAW_AUDIO;
410 	err = getRequiredInputFormat(required);
411 	ASSERT(err == B_OK);
412 
413 //	// attempt to create op? +++++
414 //
415 //	// validate against current input/output format for now
416 //	validateProposedFormat(
417 //		(m_format.u.raw_audio.format != media_raw_audio_format::wildcard.format) ?
418 //			m_format : preferred,
419 //		*ioFormat);
420 
421 	// validate against required format
422 	err = validateProposedInputFormat(required, *ioFormat);
423 	if(err < B_OK)
424 		return err;
425 
426 	// if an output connection has been made, try to create an operation
427 	if (m_output.destination != media_destination::null) {
428 		// Further specialize the format, in case of any remaining wildcards.
429 		// Special case for buffer size: make sure we use the same frame count.
430 		const bool setFrameSize = ioFormat->u.raw_audio.buffer_size
431 			== media_raw_audio_format::wildcard.buffer_size;
432 		ioFormat->SpecializeTo(&m_output.format);
433 		if (setFrameSize) {
434 			ioFormat->u.raw_audio.buffer_size =
435 				bytes_per_frame(ioFormat->u.raw_audio)
436 				* (m_output.format.u.raw_audio.buffer_size
437 					/ bytes_per_frame(m_output.format.u.raw_audio));
438 		}
439 
440 		ASSERT(m_opFactory);
441 		IAudioOp* op = m_opFactory->createOp(
442 			this,
443 			ioFormat->u.raw_audio,
444 			m_output.format.u.raw_audio);
445 
446 		if(!op) {
447 			// format passed validation, but factory failed to provide a
448 			// capable operation object
449 			char fmt[256];
450 			string_for_format(*ioFormat, fmt, 255);
451 			PRINT((
452 				"*** AcceptFormat(): format validated, but no operation found:\n"
453 				"    %s\n",
454 				fmt));
455 
456 			return B_MEDIA_BAD_FORMAT;
457 		}
458 		// clean up
459 		delete op;
460 	}
461 
462 	// format passed inspection
463 	return B_OK;
464 }
465 
466 // "If you're writing a node, and receive a buffer with the B_SMALL_BUFFER
467 //  flag set, you must recycle the buffer before returning."
468 
BufferReceived(BBuffer * buffer)469 void AudioFilterNode::BufferReceived(
470 	BBuffer*										buffer) {
471 	ASSERT(buffer);
472 
473 	// check buffer destination
474 	if(buffer->Header()->destination !=
475 		m_input.destination.id) {
476 		PRINT(("AudioFilterNode::BufferReceived():\n"
477 			"\tBad destination.\n"));
478 		buffer->Recycle();
479 		return;
480 	}
481 
482 	if(buffer->Header()->time_source != TimeSource()->ID()) { // +++++ no-go in offline mode
483 		PRINT(("* timesource mismatch\n"));
484 	}
485 
486 	// check output
487 	if(m_output.destination == media_destination::null ||
488 		!m_outputEnabled) {
489 		buffer->Recycle();
490 		return;
491 	}
492 
493 //	// +++++ [9sep99]
494 //	bigtime_t now = TimeSource()->Now();
495 //	bigtime_t delta = now - m_tpLastReceived;
496 //	m_tpLastReceived = now;
497 //	PRINT((
498 //		"### delta: %lld (%lld)\n",
499 //		delta, buffer->Header()->start_time - now));
500 
501 	// fetch outbound buffer if needed
502 	BBuffer* outBuffer;
503 	if(m_bufferGroup) {
504 		outBuffer = m_bufferGroup->RequestBuffer(
505 			m_output.format.u.raw_audio.buffer_size, -1);
506 		ASSERT(outBuffer);
507 
508 		// prepare outbound buffer
509 		outBuffer->Header()->type = B_MEDIA_RAW_AUDIO;
510 
511 		// copy start time info from upstream node
512 		// +++++ is this proper, or should the next buffer-start be
513 		//       continuously tracked (figured from Start() or the first
514 		//       buffer received?)
515 		outBuffer->Header()->time_source = buffer->Header()->time_source;
516 		outBuffer->Header()->start_time = buffer->Header()->start_time;
517 	}
518 	else {
519 		// process inplace
520 		outBuffer = buffer;
521 	}
522 
523 	// process and retransmit buffer
524 	processBuffer(buffer, outBuffer);
525 
526 	status_t err = SendBuffer(outBuffer, m_output.source, m_output.destination);
527 	if (err < B_OK) {
528 		PRINT(("AudioFilterNode::BufferReceived():\n"
529 			"\tSendBuffer() failed: %s\n", strerror(err)));
530 		outBuffer->Recycle();
531 	}
532 
533 	// free inbound buffer if data was copied
534 	if(buffer != outBuffer)
535 		buffer->Recycle();
536 
537 //	//####resend
538 //	SendBuffer(buffer, m_output.destination);
539 
540 	// sent!
541 }
542 
543 // * make sure to fill in poInput->format with the contents of
544 //   pFormat; as of R4.5 the Media Kit passes poInput->format to
545 //   the producer in BBufferProducer::Connect().
546 
Connected(const media_source & source,const media_destination & destination,const media_format & format,media_input * outInput)547 status_t AudioFilterNode::Connected(
548 	const media_source&					source,
549 	const media_destination&		destination,
550 	const media_format&					format,
551 	media_input*								outInput) {
552 
553 	PRINT(("AudioFilterNode::Connected()\n"
554 		"\tto source %" B_PRId32 "\n", source.id));
555 
556 	// sanity check
557 	if(destination != m_input.destination) {
558 		PRINT(("\tbad destination\n"));
559 		return B_MEDIA_BAD_DESTINATION;
560 	}
561 	if(m_input.source != media_source::null) {
562 		PRINT(("\talready connected\n"));
563 		return B_MEDIA_ALREADY_CONNECTED;
564 	}
565 
566 	// initialize input
567 	m_input.source = source;
568 	m_input.format = format;
569 	*outInput = m_input;
570 
571 	// [re-]initialize operation
572 	updateOperation();
573 
574 	return B_OK;
575 }
576 
Disconnected(const media_source & source,const media_destination & destination)577 void AudioFilterNode::Disconnected(
578 	const media_source&					source,
579 	const media_destination&		destination) {
580 
581 	PRINT(("AudioFilterNode::Disconnected()\n"));
582 
583 	// sanity checks
584 	if(m_input.source != source) {
585 		PRINT(("\tsource mismatch: expected ID %" B_PRId32 ", got %" B_PRId32
586 				"\n", m_input.source.id, source.id));
587 		return;
588 	}
589 	if(destination != m_input.destination) {
590 		PRINT(("\tdestination mismatch: expected ID %" B_PRId32 ", got %"
591 				B_PRId32 "\n", m_input.destination.id, destination.id));
592 		return;
593 	}
594 
595 	// mark disconnected
596 	m_input.source = media_source::null;
597 
598 #ifdef DEBUG
599 	status_t err =
600 #endif
601 	getRequiredInputFormat(m_input.format);
602 	ASSERT(err == B_OK);
603 
604 	// remove operation
605 	if(m_op) {
606 		delete m_op;
607 		m_op = 0;
608 	}
609 
610 	// +++++ further cleanup?
611 
612 	// release buffer group
613 	updateBufferGroup();
614 }
615 
616 
DisposeInputCookie(int32 cookie)617 void AudioFilterNode::DisposeInputCookie(
618 	int32												cookie) {}
619 
620 // "You should implement this function so your node will know that the data
621 //  format is going to change. Note that this may be called in response to
622 //  your AcceptFormat() call, if your AcceptFormat() call alters any wildcard
623 //  fields in the specified format.
624 //
625 //  Because FormatChanged() is called by the producer, you don't need to (and
626 //  shouldn't) ask it if the new format is acceptable.
627 //
628 //  If the format change isn't possible, return an appropriate error from
629 //  FormatChanged(); this error will be passed back to the producer that
630 //  initiated the new format negotiation in the first place."
631 
FormatChanged(const media_source & source,const media_destination & destination,int32 changeTag,const media_format & newFormat)632 status_t AudioFilterNode::FormatChanged(
633 	const media_source&					source,
634 	const media_destination&		destination,
635 	int32												changeTag,
636 	const media_format&					newFormat) {
637 
638 	// flat-out deny format changes for now +++++
639 	return B_MEDIA_BAD_FORMAT;
640 }
641 
GetLatencyFor(const media_destination & destination,bigtime_t * outLatency,media_node_id * outTimeSource)642 status_t AudioFilterNode::GetLatencyFor(
643 	const media_destination&		destination,
644 	bigtime_t*									outLatency,
645 	media_node_id*							outTimeSource) {
646 
647 	PRINT(("AudioFilterNode::GetLatencyFor()\n"));
648 
649 	// sanity check
650 	if(destination != m_input.destination) {
651 		PRINT(("\tbad destination\n"));
652 		return B_MEDIA_BAD_DESTINATION;
653 	}
654 
655 	*outLatency = m_downstreamLatency + m_processingLatency;
656 	PRINT(("\treturning %" B_PRIdBIGTIME "\n", *outLatency));
657 	*outTimeSource = TimeSource()->ID();
658 	return B_OK;
659 }
660 
GetNextInput(int32 * ioCookie,media_input * outInput)661 status_t AudioFilterNode::GetNextInput(
662 	int32*											ioCookie,
663 	media_input*								outInput) {
664 
665 	if(*ioCookie)
666 		return B_BAD_INDEX;
667 
668 	++*ioCookie;
669 	*outInput = m_input;
670 	return B_OK;
671 }
672 
673 
ProducerDataStatus(const media_destination & destination,int32 status,bigtime_t tpWhen)674 void AudioFilterNode::ProducerDataStatus(
675 	const media_destination&		destination,
676 	int32												status,
677 	bigtime_t										tpWhen) {
678 
679 	PRINT(("AudioFilterNode::ProducerDataStatus(%" B_PRId32 " at %"
680 			B_PRIdBIGTIME ")\n", status, tpWhen));
681 
682 	// sanity check
683 	if(destination != m_input.destination) {
684 		PRINT(("\tbad destination\n"));
685 	}
686 
687 	if(m_output.destination != media_destination::null) {
688 		// pass status downstream
689 		status_t err = SendDataStatus(
690 			status,
691 			m_output.destination,
692 			tpWhen);
693 		if(err < B_OK) {
694 			PRINT(("\tSendDataStatus(): %s\n", strerror(err)));
695 		}
696 	}
697 }
698 
699 // "This function is provided to aid in supporting media formats in which the
700 //  outer encapsulation layer doesn't supply timing information. Producers will
701 //  tag the buffers they generate with seek tags; these tags can be used to
702 //  locate key frames in the media data."
703 
SeekTagRequested(const media_destination & destination,bigtime_t targetTime,uint32 flags,media_seek_tag * outSeekTag,bigtime_t * outTaggedTime,uint32 * outFlags)704 status_t AudioFilterNode::SeekTagRequested(
705 	const media_destination&		destination,
706 	bigtime_t										targetTime,
707 	uint32											flags,
708 	media_seek_tag*							outSeekTag,
709 	bigtime_t*									outTaggedTime,
710 	uint32*											outFlags) {
711 
712 	// +++++
713 	PRINT(("AudioFilterNode::SeekTagRequested()\n"
714 		"\tNot implemented.\n"));
715 	return B_ERROR;
716 }
717 
718 // -------------------------------------------------------- //
719 // *** BBufferProducer
720 // -------------------------------------------------------- //
721 
722 // "When a consumer calls BBufferConsumer::RequestAdditionalBuffer(), this
723 //  function is called as a result. Its job is to call SendBuffer() to
724 //  immediately send the next buffer to the consumer. The previousBufferID,
725 //  previousTime, and previousTag arguments identify the last buffer the
726 //  consumer received. Your node should respond by sending the next buffer
727 //  after the one described.
728 //
729 //  The previousTag may be NULL.
730 //  Return B_OK if all is well; otherwise return an appropriate error code."
731 
AdditionalBufferRequested(const media_source & source,media_buffer_id previousBufferID,bigtime_t previousTime,const media_seek_tag * previousTag)732 void AudioFilterNode::AdditionalBufferRequested(
733 	const media_source&					source,
734 	media_buffer_id							previousBufferID,
735 	bigtime_t										previousTime,
736 	const media_seek_tag*				previousTag) {
737 
738 	// +++++
739 	PRINT(("AudioFilterNode::AdditionalBufferRequested\n"
740 		"\tOffline mode not implemented."));
741 }
742 
Connect(status_t status,const media_source & source,const media_destination & destination,const media_format & format,char * ioName)743 void AudioFilterNode::Connect(
744 	status_t										status,
745 	const media_source&					source,
746 	const media_destination&		destination,
747 	const media_format&					format,
748 	char*												ioName) {
749 
750 	PRINT(("AudioFilterNode::Connect()\n"));
751 	status_t err;
752 
753 #if DEBUG
754 	char formatStr[256];
755 	string_for_format(format, formatStr, 255);
756 	PRINT(("\tformat: %s\n", formatStr));
757 #endif
758 
759 	// connection failed?
760 	if(status < B_OK) {
761 		PRINT(("\tCONNECTION FAILED: Status '%s'\n", strerror(status)));
762 		// 'unreserve' the output
763 		m_output.destination = media_destination::null;
764 		return;
765 	}
766 
767 	// connection established:
768 	strncpy(ioName, m_output.name, B_MEDIA_NAME_LENGTH);
769 	m_output.destination = destination;
770 
771 	// figure downstream latency
772 	media_node_id timeSource;
773 	err = FindLatencyFor(m_output.destination, &m_downstreamLatency, &timeSource);
774 	if(err < B_OK) {
775 		PRINT(("\t!!! FindLatencyFor(): %s\n", strerror(err)));
776 	}
777 	PRINT(("\tdownstream latency = %" B_PRIdBIGTIME "\n", m_downstreamLatency));
778 
779 //	// prepare the filter
780 //	initFilter();
781 //
782 //	// figure processing time
783 //	m_processingLatency = calcProcessingLatency();
784 //	PRINT(("\tprocessing latency = %lld\n", m_processingLatency));
785 //
786 //	// store summed latency
787 //	SetEventLatency(m_downstreamLatency + m_processingLatency);
788 //
789 //	if(m_input.source != media_source::null) {
790 //		// pass new latency upstream
791 //		err = SendLatencyChange(
792 //			m_input.source,
793 //			m_input.destination,
794 //			EventLatency() + SchedulingLatency());
795 //		if(err < B_OK)
796 //			PRINT(("\t!!! SendLatencyChange(): %s\n", strerror(err)));
797 //	}
798 
799 	// cache buffer duration
800 	SetBufferDuration(
801 		buffer_duration(
802 			m_output.format.u.raw_audio));
803 
804 	// [re-]initialize operation
805 	updateOperation();
806 
807 	// initialize buffer group if necessary
808 	updateBufferGroup();
809 }
810 
Disconnect(const media_source & source,const media_destination & destination)811 void AudioFilterNode::Disconnect(
812 	const media_source&					source,
813 	const media_destination&		destination) {
814 
815 	PRINT(("AudioFilterNode::Disconnect()\n"));
816 
817 	// sanity checks
818 	if(source != m_output.source) {
819 		PRINT(("\tbad source\n"));
820 		return;
821 	}
822 	if(destination != m_output.destination) {
823 		PRINT(("\tbad destination\n"));
824 		return;
825 	}
826 
827 	// clean up
828 	m_output.destination = media_destination::null;
829 
830 #ifdef DEBUG
831 	status_t err =
832 #endif
833 	getRequiredOutputFormat(m_output.format);
834 	ASSERT(err == B_OK);
835 
836 	updateBufferGroup();
837 
838 	if(m_op) {
839 		delete m_op;
840 		m_op = 0;
841 	}
842 }
843 
DisposeOutputCookie(int32 cookie)844 status_t AudioFilterNode::DisposeOutputCookie(
845 	int32												cookie) {
846 	return B_OK;
847 }
848 
EnableOutput(const media_source & source,bool enabled,int32 * _deprecated_)849 void AudioFilterNode::EnableOutput(
850 	const media_source&					source,
851 	bool												enabled,
852 	int32* _deprecated_) {
853 
854 	PRINT(("AudioFilterNode::EnableOutput()\n"));
855 	if(source != m_output.source) {
856 		PRINT(("\tbad source\n"));
857 		return;
858 	}
859 
860 	m_outputEnabled = enabled;
861 }
862 
FormatChangeRequested(const media_source & source,const media_destination & destination,media_format * ioFormat,int32 * _deprecated_)863 status_t AudioFilterNode::FormatChangeRequested(
864 	const media_source&					source,
865 	const media_destination&		destination,
866 	media_format*								ioFormat,
867 	int32* _deprecated_) {
868 
869 	// deny +++++ for now
870 	PRINT(("AudioFilterNode::FormatChangeRequested()\n"
871 		"\tNot supported.\n"));
872 
873 	return B_MEDIA_BAD_FORMAT;
874 }
875 
FormatProposal(const media_source & source,media_format * ioFormat)876 status_t AudioFilterNode::FormatProposal(
877 	const media_source&					source,
878 	media_format*								ioFormat) {
879 
880 	PRINT(("AudioFilterNode::FormatProposal()\n"));
881 	status_t err;
882 
883 	if(source != m_output.source) {
884 		PRINT(("\tbad source\n"));
885 		return B_MEDIA_BAD_SOURCE;
886 	}
887 
888 	if(ioFormat->type != B_MEDIA_RAW_AUDIO) {
889 		PRINT(("\tbad type\n"));
890 		return B_MEDIA_BAD_FORMAT;
891 	}
892 
893 	// validate against required format
894 	media_format required;
895 	required.type = B_MEDIA_RAW_AUDIO;
896 	err = getRequiredOutputFormat(required);
897 	ASSERT(err == B_OK);
898 
899 	err = validateProposedOutputFormat(
900 		required,
901 		*ioFormat);
902 	if(err < B_OK)
903 		return err;
904 
905 //	// specialize the format
906 //	media_format testFormat = *ioFormat;
907 //	specializeOutputFormat(testFormat);
908 //
909 //	// if the input is connected, ask the factory for a matching operation
910 //	if(m_input.source != media_source::null) {
911 //		ASSERT(m_opFactory);
912 //		IAudioOp* op = m_opFactory->createOp(
913 //			this,
914 //			m_input.format.u.raw_audio,
915 //			testFormat.u.raw_audio);
916 //
917 //		if(!op) {
918 //			// format passed validation, but factory failed to provide a
919 //			// capable operation object
920 //			char fmt[256];
921 //			string_for_format(*ioFormat, fmt, 255);
922 //			PRINT((
923 //				"*** FormatProposal(): format validated, but no operation found:\n"
924 //				"    %s\n",
925 //				fmt));
926 //
927 //			return B_MEDIA_BAD_FORMAT;
928 //		}
929 //		// clean up
930 //		delete op;
931 //	}
932 
933 	// format passed inspection
934 	return B_OK;
935 }
936 
FormatSuggestionRequested(media_type type,int32 quality,media_format * outFormat)937 status_t AudioFilterNode::FormatSuggestionRequested(
938 	media_type									type,
939 	int32												quality,
940 	media_format*								outFormat) {
941 
942 	PRINT(("AudioFilterNode::FormatSuggestionRequested()\n"));
943 	if(type != B_MEDIA_RAW_AUDIO) {
944 		PRINT(("\tbad type\n"));
945 		return B_MEDIA_BAD_FORMAT;
946 	}
947 
948 	outFormat->type = type;
949 	return getPreferredOutputFormat(*outFormat);
950 }
951 
GetLatency(bigtime_t * outLatency)952 status_t AudioFilterNode::GetLatency(
953 	bigtime_t*									outLatency) {
954 
955 	PRINT(("AudioFilterNode::GetLatency()\n"));
956 	*outLatency = EventLatency() + SchedulingLatency();
957 	PRINT(("\treturning %" B_PRIdBIGTIME "\n", *outLatency));
958 
959 	return B_OK;
960 }
961 
GetNextOutput(int32 * ioCookie,media_output * outOutput)962 status_t AudioFilterNode::GetNextOutput(
963 	int32*											ioCookie,
964 	media_output*								outOutput) {
965 
966 	if(*ioCookie)
967 		return B_BAD_INDEX;
968 
969 	++*ioCookie;
970 	*outOutput = m_output;
971 
972 	return B_OK;
973 }
974 
975 
976 // "This hook function is called when a BBufferConsumer that's receiving data
977 //  from you determines that its latency has changed. It will call its
978 //  BBufferConsumer::SendLatencyChange() function, and in response, the Media
979 //  Server will call your LatencyChanged() function.  The source argument
980 //  indicates your output that's involved in the connection, and destination
981 //  specifies the input on the consumer to which the connection is linked.
982 //  newLatency is the consumer's new latency. The flags are currently unused."
LatencyChanged(const media_source & source,const media_destination & destination,bigtime_t newLatency,uint32 flags)983 void AudioFilterNode::LatencyChanged(
984 	const media_source&					source,
985 	const media_destination&		destination,
986 	bigtime_t										newLatency,
987 	uint32											flags) {
988 
989 	PRINT(("AudioFilterNode::LatencyChanged()\n"));
990 
991 	if(source != m_output.source) {
992 		PRINT(("\tBad source.\n"));
993 		return;
994 	}
995 	if(destination != m_output.destination) {
996 		PRINT(("\tBad destination.\n"));
997 		return;
998 	}
999 
1000 	m_downstreamLatency = newLatency;
1001 	SetEventLatency(m_downstreamLatency + m_processingLatency);
1002 
1003 	if(m_input.source != media_source::null) {
1004 		// pass new latency upstream
1005 		status_t err = SendLatencyChange(
1006 			m_input.source,
1007 			m_input.destination,
1008 			EventLatency() + SchedulingLatency());
1009 		if(err < B_OK)
1010 			PRINT(("\t!!! SendLatencyChange(): %s\n", strerror(err)));
1011 	}
1012 }
1013 
LateNoticeReceived(const media_source & source,bigtime_t howLate,bigtime_t tpWhen)1014 void AudioFilterNode::LateNoticeReceived(
1015 	const media_source&					source,
1016 	bigtime_t										howLate,
1017 	bigtime_t										tpWhen) {
1018 
1019 	PRINT(("AudioFilterNode::LateNoticeReceived()\n"
1020 		"\thowLate == %" B_PRIdBIGTIME "\n"
1021 		"\twhen    == %" B_PRIdBIGTIME "\n", howLate, tpWhen));
1022 
1023 	if(source != m_output.source) {
1024 		PRINT(("\tBad source.\n"));
1025 		return;
1026 	}
1027 
1028 	if(m_input.source == media_source::null) {
1029 		PRINT(("\t!!! No input to blame.\n"));
1030 		return;
1031 	}
1032 
1033 	// +++++ check run mode?
1034 
1035 	// pass the buck, since this node doesn't schedule buffer
1036 	// production
1037 	NotifyLateProducer(
1038 		m_input.source,
1039 		howLate,
1040 		tpWhen);
1041 }
1042 
1043 // PrepareToConnect() is the second stage of format negotiations that happens
1044 // inside BMediaRoster::Connect().  At this point, the consumer's AcceptFormat()
1045 // method has been called, and that node has potentially changed the proposed
1046 // format.  It may also have left wildcards in the format.  PrepareToConnect()
1047 // *must* fully specialize the format before returning!
1048 
PrepareToConnect(const media_source & source,const media_destination & destination,media_format * ioFormat,media_source * outSource,char * outName)1049 status_t AudioFilterNode::PrepareToConnect(
1050 	const media_source&					source,
1051 	const media_destination&		destination,
1052 	media_format*								ioFormat,
1053 	media_source*								outSource,
1054 	char*												outName) {
1055 
1056 	status_t err;
1057 	char formatStr[256];
1058 	string_for_format(*ioFormat, formatStr, 255);
1059 	PRINT(("AudioFilterNode::PrepareToConnect()\n"
1060 		"\tproposed format: %s\n", formatStr));
1061 
1062 	if(source != m_output.source) {
1063 		PRINT(("\tBad source.\n"));
1064 		return B_MEDIA_BAD_SOURCE;
1065 	}
1066 	if(m_output.destination != media_destination::null) {
1067 		PRINT(("\tAlready connected.\n"));
1068 		return B_MEDIA_ALREADY_CONNECTED;
1069 	}
1070 
1071 	if(ioFormat->type != B_MEDIA_RAW_AUDIO) {
1072 		PRINT(("\tBad format type.\n"));
1073 		return B_MEDIA_BAD_FORMAT;
1074 	}
1075 
1076 	// do a final validity check:
1077 	media_format required;
1078 	required.type = B_MEDIA_RAW_AUDIO;
1079 	err = getRequiredOutputFormat(required);
1080 	ASSERT(err == B_OK);
1081 
1082 	err = validateProposedOutputFormat(
1083 		required,	*ioFormat);
1084 
1085 	if(err < B_OK) {
1086 		// no go
1087 		return err;
1088 	}
1089 
1090 	// fill in wildcards
1091 	specializeOutputFormat(*ioFormat);
1092 
1093 	string_for_format(*ioFormat, formatStr, 255);
1094 	PRINT(("FINAL FORMAT: %s\n", formatStr));
1095 
1096 	// reserve the output
1097 	m_output.destination = destination;
1098 	m_output.format = *ioFormat;
1099 
1100 	// pass back source & output name
1101 	*outSource = m_output.source;
1102 	strncpy(outName, m_output.name, B_MEDIA_NAME_LENGTH);
1103 
1104 	return B_OK;
1105 }
1106 
SetBufferGroup(const media_source & source,BBufferGroup * group)1107 status_t AudioFilterNode::SetBufferGroup(
1108 	const media_source&					source,
1109 	BBufferGroup*								group) {
1110 
1111 	PRINT(("AudioFilterNode::SetBufferGroup()\n"));
1112 	if(source != m_output.source) {
1113 		PRINT(("\tBad source.\n"));
1114 		return B_MEDIA_BAD_SOURCE;
1115 	}
1116 
1117 //	if(m_input.source == media_source::null) {
1118 //		PRINT(("\tNo producer to send buffers to.\n"));
1119 //		return B_ERROR;
1120 //	}
1121 //
1122 //	// +++++ is this right?  buffer-group selection gets
1123 //	//       all asynchronous and weird...
1124 //	int32 changeTag;
1125 //	return SetOutputBuffersFor(
1126 //		m_input.source,
1127 //		m_input.destination,
1128 //		group,
1129 //		0, &changeTag);
1130 
1131 	// do it [8sep99]
1132 	if(m_bufferGroup)
1133 		delete m_bufferGroup;
1134 	m_bufferGroup = group;
1135 
1136 	return B_OK;
1137 }
1138 
SetPlayRate(int32 numerator,int32 denominator)1139 status_t AudioFilterNode::SetPlayRate(
1140 	int32												numerator,
1141 	int32												denominator) {
1142 	// not supported
1143 	return B_ERROR;
1144 }
1145 
VideoClippingChanged(const media_source & source,int16 numShorts,int16 * clipData,const media_video_display_info & display,int32 * outFromChangeTag)1146 status_t AudioFilterNode::VideoClippingChanged(
1147 	const media_source&					source,
1148 	int16												numShorts,
1149 	int16*											clipData,
1150 	const media_video_display_info& display,
1151 	int32*											outFromChangeTag) {
1152 	// not sane
1153 	return B_ERROR;
1154 }
1155 
1156 // -------------------------------------------------------- //
1157 // *** BControllable
1158 // -------------------------------------------------------- //
1159 
GetParameterValue(int32 id,bigtime_t * outLastChangeTime,void * outValue,size_t * ioSize)1160 status_t AudioFilterNode::GetParameterValue(
1161 	int32												id,
1162 	bigtime_t*									outLastChangeTime,
1163 	void*												outValue,
1164 	size_t*											ioSize) {
1165 
1166 	ASSERT(m_parameterSet);
1167 	return m_parameterSet->getValue(
1168 		id,
1169 		outLastChangeTime,
1170 		outValue,
1171 		ioSize);
1172 }
1173 
SetParameterValue(int32 id,bigtime_t changeTime,const void * value,size_t size)1174 void AudioFilterNode::SetParameterValue(
1175 	int32												id,
1176 	bigtime_t										changeTime,
1177 	const void*									value,
1178 	size_t											size) {
1179 
1180 	// not running? set parameter now
1181 	if(RunState() != B_STARTED) {
1182 		ASSERT(m_parameterSet);
1183 		m_parameterSet->setValue(
1184 			id,
1185 			changeTime,
1186 			value,
1187 			size);
1188 		return;
1189 	}
1190 
1191 	// queue a parameter-change event
1192 
1193 	if(size > 64) { // +++++ hard-coded limitation in media_timed_event
1194 		DEBUGGER((
1195 			"!!! AudioFilterNode::SetParameterValue(): parameter data too large\n"));
1196 	}
1197 
1198 	media_timed_event ev(
1199 		changeTime,
1200 		BTimedEventQueue::B_PARAMETER,
1201 		0,
1202 		BTimedEventQueue::B_NO_CLEANUP,
1203 		size,
1204 		id,
1205 		(char*)value, size);
1206 	EventQueue()->AddEvent(ev);
1207 }
1208 
1209 // -------------------------------------------------------- //
1210 // *** IAudioOpHost
1211 // -------------------------------------------------------- //
1212 
parameterSet() const1213 IParameterSet* AudioFilterNode::parameterSet() const {
1214 	return m_parameterSet;
1215 }
1216 
1217 // -------------------------------------------------------- //
1218 // HandleEvent() impl.
1219 // -------------------------------------------------------- //
1220 
handleParameterEvent(const media_timed_event * event)1221 void AudioFilterNode::handleParameterEvent(
1222 	const media_timed_event*		event) {
1223 
1224 	// retrieve encoded parameter data
1225 	void* value = (void*)event->user_data;
1226 	int32 id = event->bigdata;
1227 	size_t size = event->data;
1228 	bigtime_t changeTime = event->event_time;
1229 	status_t err;
1230 
1231 	// hand to parameter set
1232 	ASSERT(m_parameterSet);
1233 	err = m_parameterSet->setValue(id, changeTime, value, size);
1234 
1235 	if(err < B_OK) {
1236 		PRINT((
1237 			"* AudioFilterNode::handleParameterEvent(): m_parameterSet->SetValue() failed:\n"
1238 			"  %s\n", strerror(err)));
1239 	}
1240 }
1241 
handleStartEvent(const media_timed_event * event)1242 void AudioFilterNode::handleStartEvent(
1243 	const media_timed_event*		event) {
1244 	PRINT(("AudioFilterNode::handleStartEvent\n"));
1245 
1246 	// initialize the filter
1247 	ASSERT(m_op);
1248 	m_op->init();
1249 }
1250 
handleStopEvent(const media_timed_event * event)1251 void AudioFilterNode::handleStopEvent(
1252 	const media_timed_event*		event) {
1253 
1254 	PRINT(("AudioFilterNode::handleStopEvent\n"));
1255 	// +++++
1256 }
1257 
ignoreEvent(const media_timed_event * event)1258 void AudioFilterNode::ignoreEvent(
1259 	const media_timed_event*		event) {
1260 
1261 	PRINT(("AudioFilterNode::ignoreEvent\n"));
1262 }
1263 
1264 // -------------------------------------------------------- //
1265 // *** internal operations
1266 // -------------------------------------------------------- //
1267 
1268 status_t
prepareFormatChange(const media_format & newFormat)1269 AudioFilterNode::prepareFormatChange(const media_format &newFormat)
1270 {
1271 	media_format required;
1272 	required.type = B_MEDIA_RAW_AUDIO;
1273 	status_t err = getRequiredOutputFormat(required);
1274 	ASSERT(err == B_OK);
1275 
1276 	media_format proposed = newFormat;
1277 	err = validateProposedOutputFormat(
1278 		required,
1279 		proposed);
1280 	return err;
1281 }
1282 
1283 void
doFormatChange(const media_format & newFormat)1284 AudioFilterNode::doFormatChange(const media_format &newFormat)
1285 {
1286 	m_output.format = newFormat;
1287 	updateOperation();
1288 }
1289 
1290 
1291 // create and register a parameter web
initParameterWeb()1292 void AudioFilterNode::initParameterWeb() {
1293 	ASSERT(m_parameterSet);
1294 
1295 	BParameterWeb* web = new BParameterWeb();
1296 	BString groupName = B_TRANSLATE("%groupname% parameters");
1297 	groupName.ReplaceFirst("%groupname%", Name());
1298 	BParameterGroup* group = web->MakeGroup(groupName.String());
1299 	m_parameterSet->populateGroup(group);
1300 
1301 	SetParameterWeb(web);
1302 }
1303 
1304 // [re-]initialize operation if necessary
updateOperation()1305 void AudioFilterNode::updateOperation() {
1306 
1307 	if(m_input.source == media_source::null ||
1308 		m_output.destination == media_destination::null)
1309 		// not fully connected; nothing to do
1310 		return;
1311 
1312 	// ask the factory for an operation
1313 	ASSERT(m_opFactory);
1314 	IAudioOp* op = m_opFactory->createOp(
1315 		this,
1316 		m_input.format.u.raw_audio,
1317 		m_output.format.u.raw_audio);
1318 	if(!op) {
1319 		PRINT((
1320 			"!!! AudioFilterNode::updateOperation(): no operation created!\n"));
1321 
1322 		// clean up existing operation
1323 		delete m_op;
1324 		m_op = 0;
1325 		return;
1326 	}
1327 
1328 	// install new operation
1329 	op->replace(m_op);
1330 	m_op = op;
1331 
1332 	// do performance tests (what if I'm running? +++++)
1333 
1334 	m_processingLatency = calcProcessingLatency();
1335 	PRINT(("\tprocessing latency = %" B_PRIdBIGTIME "\n", m_processingLatency));
1336 
1337 	// store summed latency
1338 	SetEventLatency(m_downstreamLatency + m_processingLatency);
1339 
1340 	// pass new latency upstream
1341 	status_t err = SendLatencyChange(
1342 		m_input.source,
1343 		m_input.destination,
1344 		EventLatency() + SchedulingLatency());
1345 	if(err < B_OK)
1346 		PRINT(("\t!!! SendLatencyChange(): %s\n", strerror(err)));
1347 }
1348 
1349 
1350 // create or discard buffer group if necessary
updateBufferGroup()1351 void AudioFilterNode::updateBufferGroup() {
1352 
1353 	status_t err;
1354 
1355 	size_t inputSize = bytes_per_frame(m_input.format.u.raw_audio);
1356 	size_t outputSize = bytes_per_frame(m_output.format.u.raw_audio);
1357 
1358 	if(m_input.source == media_source::null ||
1359 		m_output.destination == media_destination::null ||
1360 		inputSize >= outputSize) {
1361 
1362 		PRINT(("###### NO BUFFER GROUP NEEDED\n"));
1363 
1364 		// no internal buffer group needed
1365 		if(m_bufferGroup) {
1366 			// does this block? +++++
1367 			delete m_bufferGroup;
1368 			m_bufferGroup = 0;
1369 		}
1370 		return;
1371 	}
1372 
1373 	int32 bufferCount = EventLatency() / BufferDuration() + 1 + 1;
1374 
1375 	// +++++
1376 	// [e.moon 27sep99] this is a reasonable number of buffers,
1377 	// but it fails with looped file-player node in BeOS 4.5.2.
1378 	//
1379 	if(bufferCount < 5)
1380 		bufferCount = 5;
1381 //	if(bufferCount < 3)
1382 //		bufferCount = 3;
1383 
1384 	if(m_bufferGroup) {
1385 
1386 		// is the current group sufficient?
1387 		int32 curBufferCount;
1388 		err = m_bufferGroup->CountBuffers(&curBufferCount);
1389 		if(err == B_OK && curBufferCount >= bufferCount) {
1390 			BBuffer* buf = m_bufferGroup->RequestBuffer(
1391 				outputSize, -1);
1392 
1393 			if(buf) {
1394 				// yup
1395 				buf->Recycle();
1396 				return;
1397 			}
1398 		}
1399 
1400 		// nope, delete it to make way for the new one
1401 		delete m_bufferGroup;
1402 		m_bufferGroup = 0;
1403 	}
1404 
1405 	// create buffer group
1406 	PRINT((
1407 		"##### AudioFilterNode::updateBufferGroup():\n"
1408 		"##### creating %" B_PRId32 " buffers of size %" B_PRIuSIZE "\n",
1409 		bufferCount, m_output.format.u.raw_audio.buffer_size));
1410 
1411 	m_bufferGroup = new BBufferGroup(
1412 		m_output.format.u.raw_audio.buffer_size,
1413 		bufferCount);
1414 }
1415 
1416 
1417 // figure processing latency by doing 'dry runs' of processBuffer()
calcProcessingLatency()1418 bigtime_t AudioFilterNode::calcProcessingLatency() {
1419 
1420 	PRINT(("AudioFilterNode::calcProcessingLatency()\n"));
1421 
1422 	ASSERT(m_input.source != media_source::null);
1423 	ASSERT(m_output.destination != media_destination::null);
1424 	ASSERT(m_op);
1425 
1426 	// initialize filter
1427 	m_op->init();
1428 
1429 	size_t maxSize = max_c(
1430 		m_input.format.u.raw_audio.buffer_size,
1431 		m_output.format.u.raw_audio.buffer_size);
1432 
1433 	// allocate a temporary buffer group
1434 	BBufferGroup* testGroup = new BBufferGroup(
1435 		maxSize, 1);
1436 
1437 	// fetch a buffer big enough for in-place processing
1438 	BBuffer* buffer = testGroup->RequestBuffer(
1439 		maxSize, -1);
1440 	ASSERT(buffer);
1441 
1442 	buffer->Header()->type = B_MEDIA_RAW_AUDIO;
1443 	buffer->Header()->size_used = m_input.format.u.raw_audio.buffer_size;
1444 
1445 	// run the test
1446 	bigtime_t preTest = system_time();
1447 	processBuffer(buffer, buffer);
1448 	bigtime_t elapsed = system_time()-preTest;
1449 
1450 	// clean up
1451 	buffer->Recycle();
1452 	delete testGroup;
1453 
1454 	// reset filter state
1455 	m_op->init();
1456 
1457 	return elapsed;// + 100000LL;
1458 }
1459 
1460 // filter buffer data; inputBuffer and outputBuffer may be identical!
1461 
processBuffer(BBuffer * inputBuffer,BBuffer * outputBuffer)1462 void AudioFilterNode::processBuffer(
1463 	BBuffer*										inputBuffer,
1464 	BBuffer*										outputBuffer) {
1465 
1466 	ASSERT(inputBuffer);
1467 	ASSERT(outputBuffer);
1468 	ASSERT(m_op);
1469 
1470 	// create wrapper objects
1471 	AudioBuffer input(m_input.format.u.raw_audio, inputBuffer);
1472 	AudioBuffer output(m_output.format.u.raw_audio, outputBuffer);
1473 
1474 	double sourceOffset = 0.0;
1475 	uint32 destinationOffset = 0L;
1476 
1477 	// when is the first frame due to be consumed?
1478 	bigtime_t startTime = outputBuffer->Header()->start_time;
1479 	// when is the next frame to be produced going to be consumed?
1480 	bigtime_t targetTime = startTime;
1481 	// when will the first frame of the next buffer be consumed?
1482 	bigtime_t endTime = startTime + BufferDuration();
1483 
1484 	uint32 framesRemaining = input.frames();
1485 	while(framesRemaining) {
1486 
1487 		// handle all events occurring before targetTime
1488 		// +++++
1489 
1490 		bigtime_t nextEventTime = endTime;
1491 
1492 		// look for next event occurring before endTime
1493 		// +++++
1494 
1495 		// process up to found event, if any, or to end of buffer
1496 
1497 		int64 toProcess = frames_for_duration(output.format(), nextEventTime - targetTime);
1498 
1499 		ASSERT(toProcess > 0);
1500 
1501 		if (toProcess > framesRemaining)
1502 			toProcess = framesRemaining;
1503 
1504 		uint32 processed = m_op->process(
1505 			input, output, sourceOffset, destinationOffset, (uint32)toProcess, targetTime);
1506 		if(processed < toProcess) {
1507 			// +++++ in offline mode this will have to request additional buffer(s), right?
1508 			PRINT((
1509 				"*** AudioFilterNode::processBuffer(): insufficient frames filled\n"));
1510 		}
1511 
1512 		framesRemaining -= toProcess;
1513 
1514 		// advance target time
1515 		targetTime = nextEventTime; // +++++ might this drift from the real frame offset?
1516 	}
1517 
1518 	outputBuffer->Header()->size_used = input.frames() * bytes_per_frame(m_output.format.u.raw_audio);
1519 //	PRINT(("### output size: %ld\n", outputBuffer->Header()->size_used));
1520 }
1521 
1522 // END -- AudioFilterNode.cpp --
1523