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
64enum input_id_t {
65	ID_AUDIO_INPUT
66};
67
68// output-ID symbols
69enum 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
91status_t AudioFilterNode::getPreferredInputFormat(
92	media_format&								ioFormat) {
93	return getPreferredOutputFormat(ioFormat);
94}
95
96status_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
119status_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
155status_t AudioFilterNode::validateProposedInputFormat(
156	const media_format&					preferredFormat,
157	media_format&								ioProposedFormat) {
158
159	return _validate_raw_audio_format(
160		preferredFormat, ioProposedFormat);
161}
162
163status_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
172void 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
213AudioFilterNode::~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
224AudioFilterNode::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
263status_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
280BMediaAddOn* AudioFilterNode::AddOn(
281	int32*											outID) const {
282
283	if(m_addOn)
284		*outID = 0;
285	return m_addOn;
286}
287
288void 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
306void 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
339void 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
381bigtime_t AudioFilterNode::OfflineTime() {
382	// +++++ offline mode not implemented +++++
383	return 0LL;
384}
385
386
387// -------------------------------------------------------- //
388// *** BBufferConsumer
389// -------------------------------------------------------- //
390
391status_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
469void 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
547status_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
577void 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
617void 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
632status_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
642status_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
661status_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
674void 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
704status_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
732void 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
743void 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
811void 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
844status_t AudioFilterNode::DisposeOutputCookie(
845	int32												cookie) {
846	return B_OK;
847}
848
849void 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
863status_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
876status_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
937status_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
952status_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
962status_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."
983void 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
1014void 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
1049status_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
1107status_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
1139status_t AudioFilterNode::SetPlayRate(
1140	int32												numerator,
1141	int32												denominator) {
1142	// not supported
1143	return B_ERROR;
1144}
1145
1146status_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
1160status_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
1174void 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
1213IParameterSet* AudioFilterNode::parameterSet() const {
1214	return m_parameterSet;
1215}
1216
1217// -------------------------------------------------------- //
1218// HandleEvent() impl.
1219// -------------------------------------------------------- //
1220
1221void 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
1242void 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
1251void AudioFilterNode::handleStopEvent(
1252	const media_timed_event*		event) {
1253
1254	PRINT(("AudioFilterNode::handleStopEvent\n"));
1255	// +++++
1256}
1257
1258void AudioFilterNode::ignoreEvent(
1259	const media_timed_event*		event) {
1260
1261	PRINT(("AudioFilterNode::ignoreEvent\n"));
1262}
1263
1264// -------------------------------------------------------- //
1265// *** internal operations
1266// -------------------------------------------------------- //
1267
1268status_t
1269AudioFilterNode::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
1283void
1284AudioFilterNode::doFormatChange(const media_format &newFormat)
1285{
1286	m_output.format = newFormat;
1287	updateOperation();
1288}
1289
1290
1291// create and register a parameter web
1292void 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
1305void 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
1351void 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()
1418bigtime_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
1462void 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