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