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