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