1 /* 2 * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr) 3 * Distributed under the terms of the MIT License. 4 */ 5 6 //! Multi-audio replacement media addon for BeOS 7 8 #include "MultiAudioNode.h" 9 10 #include <stdio.h> 11 #include <string.h> 12 13 #include <Buffer.h> 14 #include <BufferGroup.h> 15 #include <ParameterWeb.h> 16 17 #include "MultiAudioUtility.h" 18 #ifdef DEBUG 19 # define PRINTING 20 #endif 21 #include "debug.h" 22 23 class node_input { 24 public: 25 node_input(media_input& input, media_format format); 26 ~node_input(); 27 28 int32 fChannelId; 29 media_input fInput; 30 media_format fPreferredFormat; 31 media_format fFormat; 32 uint32 fBufferCycle; 33 multi_buffer_info fOldBufferInfo; 34 BBuffer* fBuffer; 35 }; 36 37 class node_output { 38 public: 39 node_output(media_output& output, media_format format); 40 ~node_output(); 41 42 int32 fChannelId; 43 media_output fOutput; 44 media_format fPreferredFormat; 45 media_format fFormat; 46 47 BBufferGroup* fBufferGroup; 48 bool fOutputEnabled; 49 uint64 fSamplesSent; 50 volatile uint32 fBufferCycle; 51 multi_buffer_info fOldBufferInfo; 52 }; 53 54 55 const char* kMultiControlString[] = { 56 "NAME IS ATTACHED", 57 "Output", "Input", "Setup", "Tone Control", "Extended Setup", "Enhanced Setup", "Master", 58 "Beep", "Phone", "Mic", "Line", "CD", "Video", "Aux", "Wave", "Gain", "Level", "Volume", 59 "Mute", "Enable", "Stereo Mix", "Mono Mix", "Output Stereo Mix", "Output Mono Mix", "Output Bass", 60 "Output Treble", "Output 3D Center", "Output 3D Depth" 61 }; 62 63 64 node_input::node_input(media_input& input, media_format format) 65 { 66 CALLED(); 67 fInput = input; 68 fPreferredFormat = format; 69 fBufferCycle = 1; 70 fBuffer = NULL; 71 } 72 73 74 node_input::~node_input() 75 { 76 CALLED(); 77 } 78 79 80 // #pragma mark - 81 82 83 node_output::node_output(media_output& output, media_format format) 84 : 85 fBufferGroup(NULL), 86 fOutputEnabled(true) 87 { 88 CALLED(); 89 fOutput = output; 90 fPreferredFormat = format; 91 fBufferCycle = 1; 92 } 93 94 95 node_output::~node_output() 96 { 97 CALLED(); 98 } 99 100 101 // #pragma mark - 102 103 104 MultiAudioNode::MultiAudioNode(BMediaAddOn* addon, const char* name, 105 MultiAudioDevice* device, int32 internalID, BMessage* config) 106 : BMediaNode(name), BBufferConsumer(B_MEDIA_RAW_AUDIO), 107 BBufferProducer(B_MEDIA_RAW_AUDIO), 108 fThread(-1), 109 fDevice(device), 110 fTimeSourceStarted(false), 111 fWeb(NULL), 112 fConfig(*config) 113 { 114 CALLED(); 115 fInitStatus = B_NO_INIT; 116 117 if (!device) 118 return; 119 120 fAddOn = addon; 121 fId = internalID; 122 123 AddNodeKind(B_PHYSICAL_OUTPUT); 124 AddNodeKind(B_PHYSICAL_INPUT); 125 126 // initialize our preferred format object 127 memset(&fPreferredFormat, 0, sizeof(fPreferredFormat)); // set everything to wildcard first 128 fPreferredFormat.type = B_MEDIA_RAW_AUDIO; 129 fPreferredFormat.u.raw_audio.format = MultiAudio::convert_to_media_format(fDevice->FormatInfo().output.format); 130 fPreferredFormat.u.raw_audio.valid_bits = MultiAudio::convert_to_valid_bits(fDevice->FormatInfo().output.format); 131 fPreferredFormat.u.raw_audio.channel_count = 2; 132 fPreferredFormat.u.raw_audio.frame_rate = MultiAudio::convert_to_sample_rate(fDevice->FormatInfo().input.rate); // measured in Hertz 133 fPreferredFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; 134 135 // we'll use the consumer's preferred buffer size, if any 136 fPreferredFormat.u.raw_audio.buffer_size = fDevice->BufferList().return_record_buffer_size 137 * (fPreferredFormat.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) 138 * fPreferredFormat.u.raw_audio.channel_count; 139 140 if (config) { 141 PRINT_OBJECT(*config); 142 } 143 144 fInitStatus = B_OK; 145 } 146 147 148 MultiAudioNode::~MultiAudioNode() 149 { 150 CALLED(); 151 fAddOn->GetConfigurationFor(this, NULL); 152 153 _StopThread(); 154 BMediaEventLooper::Quit(); 155 156 fWeb = NULL; 157 } 158 159 160 status_t 161 MultiAudioNode::InitCheck() const 162 { 163 CALLED(); 164 return fInitStatus; 165 } 166 167 168 // -------------------------------------------------------- // 169 // implementation of BMediaNode 170 // -------------------------------------------------------- // 171 172 BMediaAddOn* 173 MultiAudioNode::AddOn(int32* _internalID) const 174 { 175 CALLED(); 176 // BeBook says this only gets called if we were in an add-on. 177 if (fAddOn != 0 && _internalID != NULL) 178 *_internalID = fId; 179 180 return fAddOn; 181 } 182 183 184 void 185 MultiAudioNode::Preroll() 186 { 187 CALLED(); 188 // XXX:Performance opportunity 189 BMediaNode::Preroll(); 190 } 191 192 193 status_t 194 MultiAudioNode::HandleMessage(int32 message, const void* data, size_t size) 195 { 196 CALLED(); 197 return B_ERROR; 198 } 199 200 201 void 202 MultiAudioNode::NodeRegistered() 203 { 204 CALLED(); 205 206 if (fInitStatus != B_OK) { 207 ReportError(B_NODE_IN_DISTRESS); 208 return; 209 } 210 211 SetPriority(B_REAL_TIME_PRIORITY); 212 Run(); 213 214 node_input *currentInput = NULL; 215 int32 currentId = 0; 216 217 for (int32 i = 0; i < fDevice->Description().output_channel_count; i++) { 218 if (currentInput == NULL 219 || (fDevice->Description().channels[i].designations & B_CHANNEL_MONO_BUS) 220 || (fDevice->Description().channels[currentId].designations & B_CHANNEL_STEREO_BUS 221 && ( fDevice->Description().channels[i].designations & B_CHANNEL_LEFT || 222 !(fDevice->Description().channels[i].designations & B_CHANNEL_STEREO_BUS))) 223 || (fDevice->Description().channels[currentId].designations & B_CHANNEL_SURROUND_BUS 224 && ( fDevice->Description().channels[i].designations & B_CHANNEL_LEFT || 225 !(fDevice->Description().channels[i].designations & B_CHANNEL_SURROUND_BUS))) 226 ) { 227 PRINT(("NodeRegistered() : creating an input for %i\n", i)); 228 PRINT(("%ld\t%d\t0x%lx\t0x%lx\n", 229 fDevice->Description().channels[i].channel_id, 230 fDevice->Description().channels[i].kind, 231 fDevice->Description().channels[i].designations, 232 fDevice->Description().channels[i].connectors)); 233 234 media_input* input = new media_input; 235 236 input->format = fPreferredFormat; 237 input->destination.port = ControlPort(); 238 input->destination.id = fInputs.CountItems(); 239 input->node = Node(); 240 sprintf(input->name, "output %ld", input->destination.id); 241 242 currentInput = new node_input(*input, fPreferredFormat); 243 currentInput->fPreferredFormat.u.raw_audio.channel_count = 1; 244 currentInput->fInput.format = currentInput->fPreferredFormat; 245 246 currentInput->fChannelId = fDevice->Description().channels[i].channel_id; 247 fInputs.AddItem(currentInput); 248 249 currentId = i; 250 } else { 251 PRINT(("NodeRegistered() : adding a channel\n")); 252 currentInput->fPreferredFormat.u.raw_audio.channel_count++; 253 currentInput->fInput.format = currentInput->fPreferredFormat; 254 } 255 currentInput->fInput.format.u.raw_audio.format = media_raw_audio_format::wildcard.format; 256 } 257 258 node_output *currentOutput = NULL; 259 currentId = 0; 260 261 for (int32 i = fDevice->Description().output_channel_count; 262 i < fDevice->Description().output_channel_count 263 + fDevice->Description().input_channel_count; i++) { 264 if (currentOutput == NULL 265 || (fDevice->Description().channels[i].designations & B_CHANNEL_MONO_BUS) 266 || (fDevice->Description().channels[currentId].designations & B_CHANNEL_STEREO_BUS 267 && ( fDevice->Description().channels[i].designations & B_CHANNEL_LEFT || 268 !(fDevice->Description().channels[i].designations & B_CHANNEL_STEREO_BUS))) 269 || (fDevice->Description().channels[currentId].designations & B_CHANNEL_SURROUND_BUS 270 && ( fDevice->Description().channels[i].designations & B_CHANNEL_LEFT || 271 !(fDevice->Description().channels[i].designations & B_CHANNEL_SURROUND_BUS))) 272 ) { 273 PRINT(("NodeRegistered() : creating an output for %i\n", i)); 274 PRINT(("%ld\t%d\t0x%lx\t0x%lx\n",fDevice->Description().channels[i].channel_id, 275 fDevice->Description().channels[i].kind, 276 fDevice->Description().channels[i].designations, 277 fDevice->Description().channels[i].connectors)); 278 279 media_output *output = new media_output; 280 281 output->format = fPreferredFormat; 282 output->destination = media_destination::null; 283 output->source.port = ControlPort(); 284 output->source.id = fOutputs.CountItems(); 285 output->node = Node(); 286 sprintf(output->name, "input %ld", output->source.id); 287 288 currentOutput = new node_output(*output, fPreferredFormat); 289 currentOutput->fPreferredFormat.u.raw_audio.channel_count = 1; 290 currentOutput->fOutput.format = currentOutput->fPreferredFormat; 291 currentOutput->fChannelId = fDevice->Description().channels[i].channel_id; 292 fOutputs.AddItem(currentOutput); 293 294 currentId = i; 295 } else { 296 PRINT(("NodeRegistered() : adding a channel\n")); 297 currentOutput->fPreferredFormat.u.raw_audio.channel_count++; 298 currentOutput->fOutput.format = currentOutput->fPreferredFormat; 299 } 300 } 301 302 // Set up our parameter web 303 fWeb = MakeParameterWeb(); 304 SetParameterWeb(fWeb); 305 306 /* apply configuration */ 307 #ifdef PRINTING 308 bigtime_t start = system_time(); 309 #endif 310 311 int32 index = 0; 312 int32 parameterID = 0; 313 const void *data; 314 ssize_t size; 315 while (fConfig.FindInt32("parameterID", index, ¶meterID) == B_OK) { 316 if (fConfig.FindData("parameterData", B_RAW_TYPE, index, &data, &size) 317 == B_OK) { 318 SetParameterValue(parameterID, TimeSource()->Now(), data, size); 319 } 320 index++; 321 } 322 323 PRINT(("apply configuration in : %ld\n", system_time() - start)); 324 } 325 326 327 status_t 328 MultiAudioNode::RequestCompleted(const media_request_info& info) 329 { 330 CALLED(); 331 return B_OK; 332 } 333 334 335 void 336 MultiAudioNode::SetTimeSource(BTimeSource* timeSource) 337 { 338 CALLED(); 339 } 340 341 342 // #pragma mark - BBufferConsumer 343 344 345 // Check to make sure the format is okay, then remove 346 // any wildcards corresponding to our requirements. 347 status_t 348 MultiAudioNode::AcceptFormat(const media_destination& dest, 349 media_format* format) 350 { 351 CALLED(); 352 353 if (format == NULL) 354 return B_BAD_VALUE; 355 if (format->type != B_MEDIA_RAW_AUDIO) 356 return B_MEDIA_BAD_FORMAT; 357 358 node_input *channel = _FindInput(dest); 359 if (channel == NULL) 360 return B_MEDIA_BAD_DESTINATION; 361 362 /* media_format * myFormat = GetFormat(); 363 fprintf(stderr,"proposed format: "); 364 print_media_format(format); 365 fprintf(stderr,"\n"); 366 fprintf(stderr,"my format: "); 367 print_media_format(myFormat); 368 fprintf(stderr,"\n");*/ 369 // Be's format_is_compatible doesn't work. 370 // if (!format_is_compatible(*format,*myFormat)) { 371 372 channel->fFormat = channel->fPreferredFormat; 373 374 /*if(format->u.raw_audio.format == media_raw_audio_format::B_AUDIO_FLOAT 375 && channel->fPreferredFormat.u.raw_audio.format == media_raw_audio_format::B_AUDIO_SHORT) 376 format->u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; 377 else*/ 378 format->u.raw_audio.format = channel->fPreferredFormat.u.raw_audio.format; 379 format->u.raw_audio.valid_bits = channel->fPreferredFormat.u.raw_audio.valid_bits; 380 381 format->u.raw_audio.frame_rate = channel->fPreferredFormat.u.raw_audio.frame_rate; 382 format->u.raw_audio.channel_count = channel->fPreferredFormat.u.raw_audio.channel_count; 383 format->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; 384 format->u.raw_audio.buffer_size = fDevice->BufferList().return_playback_buffer_size 385 * (format->u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) 386 * format->u.raw_audio.channel_count; 387 388 /*media_format myFormat; 389 GetFormat(&myFormat); 390 if (!format_is_acceptible(*format,myFormat)) { 391 fprintf(stderr,"<- B_MEDIA_BAD_FORMAT\n"); 392 return B_MEDIA_BAD_FORMAT; 393 }*/ 394 //AddRequirements(format); 395 return B_OK; 396 } 397 398 399 status_t 400 MultiAudioNode::GetNextInput(int32* cookie, media_input* _input) 401 { 402 CALLED(); 403 if (_input == NULL) 404 return B_BAD_VALUE; 405 406 if (*cookie >= fInputs.CountItems() || *cookie < 0) 407 return B_BAD_INDEX; 408 409 node_input *channel = (node_input *)fInputs.ItemAt(*cookie); 410 *_input = channel->fInput; 411 *cookie += 1; 412 PRINT(("input.format : %u\n", channel->fInput.format.u.raw_audio.format)); 413 return B_OK; 414 } 415 416 417 void 418 MultiAudioNode::DisposeInputCookie(int32 cookie) 419 { 420 CALLED(); 421 // nothing to do since our cookies are just integers 422 } 423 424 425 void 426 MultiAudioNode::BufferReceived(BBuffer* buffer) 427 { 428 //CALLED(); 429 switch (buffer->Header()->type) { 430 /*case B_MEDIA_PARAMETERS: 431 { 432 status_t status = ApplyParameterData(buffer->Data(),buffer->SizeUsed()); 433 if (status != B_OK) { 434 fprintf(stderr,"ApplyParameterData in MultiAudioNode::BufferReceived failed\n"); 435 } 436 buffer->Recycle(); 437 } 438 break;*/ 439 case B_MEDIA_RAW_AUDIO: 440 if (buffer->Flags() & BBuffer::B_SMALL_BUFFER) { 441 fprintf(stderr,"NOT IMPLEMENTED: B_SMALL_BUFFER in MultiAudioNode::BufferReceived\n"); 442 // XXX: implement this part 443 buffer->Recycle(); 444 } else { 445 media_timed_event event(buffer->Header()->start_time, BTimedEventQueue::B_HANDLE_BUFFER, 446 buffer, BTimedEventQueue::B_RECYCLE_BUFFER); 447 status_t status = EventQueue()->AddEvent(event); 448 if (status != B_OK) { 449 fprintf(stderr,"EventQueue()->AddEvent(event) in MultiAudioNode::BufferReceived failed\n"); 450 buffer->Recycle(); 451 } 452 } 453 break; 454 default: 455 fprintf(stderr,"unexpected buffer type in MultiAudioNode::BufferReceived\n"); 456 buffer->Recycle(); 457 break; 458 } 459 } 460 461 462 void 463 MultiAudioNode::ProducerDataStatus(const media_destination& forWhom, 464 int32 status, bigtime_t atPerformanceTime) 465 { 466 //CALLED(); 467 468 node_input *channel = _FindInput(forWhom); 469 if (channel == NULL) { 470 fprintf(stderr,"invalid destination received in MultiAudioNode::ProducerDataStatus\n"); 471 return; 472 } 473 474 media_timed_event event(atPerformanceTime, BTimedEventQueue::B_DATA_STATUS, 475 &channel->fInput, BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL); 476 EventQueue()->AddEvent(event); 477 } 478 479 480 status_t 481 MultiAudioNode::GetLatencyFor(const media_destination& forWhom, 482 bigtime_t* _latency, media_node_id* _timeSource) 483 { 484 CALLED(); 485 if (_latency == NULL || _timeSource == NULL) 486 return B_BAD_VALUE; 487 488 node_input *channel = _FindInput(forWhom); 489 if (channel == NULL) 490 return B_MEDIA_BAD_DESTINATION; 491 492 *_latency = EventLatency(); 493 *_timeSource = TimeSource()->ID(); 494 return B_OK; 495 } 496 497 498 status_t 499 MultiAudioNode::Connected(const media_source& producer, 500 const media_destination& where, const media_format& with_format, 501 media_input* out_input) 502 { 503 CALLED(); 504 if (out_input == 0) { 505 fprintf(stderr,"<- B_BAD_VALUE\n"); 506 return B_BAD_VALUE; // no crashing 507 } 508 509 node_input *channel = _FindInput(where); 510 511 if(channel==NULL) { 512 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 513 return B_MEDIA_BAD_DESTINATION; 514 } 515 516 // use one buffer length latency 517 fInternalLatency = with_format.u.raw_audio.buffer_size * 10000 / 2 518 / ( (with_format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) 519 * with_format.u.raw_audio.channel_count) 520 / ((int32)(with_format.u.raw_audio.frame_rate / 100)); 521 522 PRINT((" internal latency = %lld\n",fInternalLatency)); 523 524 SetEventLatency(fInternalLatency); 525 526 // record the agreed upon values 527 channel->fInput.source = producer; 528 channel->fInput.format = with_format; 529 *out_input = channel->fInput; 530 531 // we are sure the thread is started 532 _StartThread(); 533 534 return B_OK; 535 } 536 537 538 void 539 MultiAudioNode::Disconnected(const media_source& producer, 540 const media_destination& where) 541 { 542 CALLED(); 543 node_input *channel = _FindInput(where); 544 545 if (channel == NULL || channel->fInput.source != producer) 546 return; 547 548 channel->fInput.source = media_source::null; 549 channel->fInput.format = channel->fPreferredFormat; 550 _FillWithZeros(*channel); 551 //GetFormat(&channel->fInput.format); 552 } 553 554 555 status_t 556 MultiAudioNode::FormatChanged(const media_source& producer, 557 const media_destination& consumer, int32 change_tag, 558 const media_format& format) 559 { 560 CALLED(); 561 node_input *channel = _FindInput(consumer); 562 563 if(channel==NULL) { 564 fprintf(stderr,"<- B_MEDIA_BAD_DESTINATION\n"); 565 return B_MEDIA_BAD_DESTINATION; 566 } 567 if (channel->fInput.source != producer) { 568 return B_MEDIA_BAD_SOURCE; 569 } 570 571 return B_ERROR; 572 } 573 574 575 status_t 576 MultiAudioNode::SeekTagRequested(const media_destination& destination, 577 bigtime_t in_target_time, 578 uint32 in_flags, 579 media_seek_tag * out_seek_tag, 580 bigtime_t * out_tagged_time, 581 uint32 * out_flags) 582 { 583 CALLED(); 584 return BBufferConsumer::SeekTagRequested(destination,in_target_time,in_flags, 585 out_seek_tag,out_tagged_time,out_flags); 586 } 587 588 589 // #pragma mark - BBufferProducer 590 591 592 status_t 593 MultiAudioNode::FormatSuggestionRequested(media_type type, int32 /*quality*/, 594 media_format* format) 595 { 596 // FormatSuggestionRequested() is not necessarily part of the format negotiation 597 // process; it's simply an interrogation -- the caller wants to see what the node's 598 // preferred data format is, given a suggestion by the caller. 599 CALLED(); 600 601 if (!format) 602 { 603 fprintf(stderr, "\tERROR - NULL format pointer passed in!\n"); 604 return B_BAD_VALUE; 605 } 606 607 // this is the format we'll be returning (our preferred format) 608 *format = fPreferredFormat; 609 610 // a wildcard type is okay; we can specialize it 611 if (type == B_MEDIA_UNKNOWN_TYPE) type = B_MEDIA_RAW_AUDIO; 612 613 // we only support raw audio 614 if (type != B_MEDIA_RAW_AUDIO) return B_MEDIA_BAD_FORMAT; 615 else return B_OK; 616 } 617 618 619 status_t 620 MultiAudioNode::FormatProposal(const media_source& output, media_format* format) 621 { 622 // FormatProposal() is the first stage in the BMediaRoster::Connect() process. We hand 623 // out a suggested format, with wildcards for any variations we support. 624 CALLED(); 625 node_output *channel = _FindOutput(output); 626 627 // is this a proposal for our select output? 628 if (channel == NULL) 629 { 630 fprintf(stderr, "MultiAudioNode::FormatProposal returning B_MEDIA_BAD_SOURCE\n"); 631 return B_MEDIA_BAD_SOURCE; 632 } 633 634 // we only support floating-point raw audio, so we always return that, but we 635 // supply an error code depending on whether we found the proposal acceptable. 636 media_type requestedType = format->type; 637 *format = channel->fPreferredFormat; 638 if ((requestedType != B_MEDIA_UNKNOWN_TYPE) && (requestedType != B_MEDIA_RAW_AUDIO)) 639 { 640 fprintf(stderr, "MultiAudioNode::FormatProposal returning B_MEDIA_BAD_FORMAT\n"); 641 return B_MEDIA_BAD_FORMAT; 642 } 643 else return B_OK; // raw audio or wildcard type, either is okay by us 644 } 645 646 647 status_t 648 MultiAudioNode::FormatChangeRequested(const media_source& source, 649 const media_destination& destination, media_format* format, 650 int32* _deprecated_) 651 { 652 CALLED(); 653 654 // we don't support any other formats, so we just reject any format changes. 655 return B_ERROR; 656 } 657 658 659 status_t 660 MultiAudioNode::GetNextOutput(int32* cookie, media_output* out_output) 661 { 662 CALLED(); 663 664 if ((*cookie < fOutputs.CountItems()) && (*cookie >= 0)) { 665 node_output *channel = (node_output *)fOutputs.ItemAt(*cookie); 666 *out_output = channel->fOutput; 667 *cookie += 1; 668 return B_OK; 669 } else 670 return B_BAD_INDEX; 671 } 672 673 674 status_t 675 MultiAudioNode::DisposeOutputCookie(int32 cookie) 676 { 677 CALLED(); 678 // do nothing because we don't use the cookie for anything special 679 return B_OK; 680 } 681 682 683 status_t 684 MultiAudioNode::SetBufferGroup(const media_source& for_source, 685 BBufferGroup* newGroup) 686 { 687 CALLED(); 688 689 node_output *channel = _FindOutput(for_source); 690 691 // is this our output? 692 if (channel == NULL) 693 { 694 fprintf(stderr, "MultiAudioNode::SetBufferGroup returning B_MEDIA_BAD_SOURCE\n"); 695 return B_MEDIA_BAD_SOURCE; 696 } 697 698 // Are we being passed the buffer group we're already using? 699 if (newGroup == channel->fBufferGroup) return B_OK; 700 701 // Ahh, someone wants us to use a different buffer group. At this point we delete 702 // the one we are using and use the specified one instead. If the specified group is 703 // NULL, we need to recreate one ourselves, and use *that*. Note that if we're 704 // caching a BBuffer that we requested earlier, we have to Recycle() that buffer 705 // *before* deleting the buffer group, otherwise we'll deadlock waiting for that 706 // buffer to be recycled! 707 delete channel->fBufferGroup; // waits for all buffers to recycle 708 if (newGroup != NULL) 709 { 710 // we were given a valid group; just use that one from now on 711 channel->fBufferGroup = newGroup; 712 } 713 else 714 { 715 // we were passed a NULL group pointer; that means we construct 716 // our own buffer group to use from now on 717 size_t size = channel->fOutput.format.u.raw_audio.buffer_size; 718 int32 count = int32(fLatency / BufferDuration() + 1 + 1); 719 channel->fBufferGroup = new BBufferGroup(size, count); 720 } 721 722 return B_OK; 723 } 724 725 726 status_t 727 MultiAudioNode::PrepareToConnect(const media_source& what, 728 const media_destination& where, media_format* format, 729 media_source* source, char* name) 730 { 731 CALLED(); 732 733 // is this our output? 734 node_output* channel = _FindOutput(what); 735 if (channel == NULL) { 736 fprintf(stderr, "MultiAudioNode::PrepareToConnect returning B_MEDIA_BAD_SOURCE\n"); 737 return B_MEDIA_BAD_SOURCE; 738 } 739 740 // are we already connected? 741 if (channel->fOutput.destination != media_destination::null) 742 return B_MEDIA_ALREADY_CONNECTED; 743 744 // the format may not yet be fully specialized (the consumer might have 745 // passed back some wildcards). Finish specializing it now, and return an 746 // error if we don't support the requested format. 747 if (format->type != B_MEDIA_RAW_AUDIO) { 748 fprintf(stderr, "\tnon-raw-audio format?!\n"); 749 return B_MEDIA_BAD_FORMAT; 750 } 751 752 // !!! validate all other fields except for buffer_size here, because the 753 // consumer might have supplied different values from AcceptFormat()? 754 755 // check the buffer size, which may still be wildcarded 756 if (format->u.raw_audio.buffer_size 757 == media_raw_audio_format::wildcard.buffer_size) { 758 format->u.raw_audio.buffer_size = 2048; 759 // pick something comfortable to suggest 760 fprintf(stderr, "\tno buffer size provided, suggesting %lu\n", 761 format->u.raw_audio.buffer_size); 762 } else { 763 fprintf(stderr, "\tconsumer suggested buffer_size %lu\n", 764 format->u.raw_audio.buffer_size); 765 } 766 767 // Now reserve the connection, and return information about it 768 channel->fOutput.destination = where; 769 channel->fOutput.format = *format; 770 771 *source = channel->fOutput.source; 772 #ifdef __HAIKU__ 773 strlcpy(name, channel->fOutput.name, B_MEDIA_NAME_LENGTH); 774 #else 775 strncpy(name, channel->fOutput.name, B_MEDIA_NAME_LENGTH); 776 #endif 777 return B_OK; 778 } 779 780 781 void 782 MultiAudioNode::Connect(status_t error, const media_source& source, 783 const media_destination& destination, const media_format& format, 784 char* name) 785 { 786 CALLED(); 787 788 // is this our output? 789 node_output* channel = _FindOutput(source); 790 if (channel == NULL) { 791 fprintf(stderr, "MultiAudioNode::Connect returning (cause : B_MEDIA_BAD_SOURCE)\n"); 792 return; 793 } 794 795 // If something earlier failed, Connect() might still be called, but with 796 // a non-zero error code. When that happens we simply unreserve the 797 // connection and do nothing else. 798 if (error) { 799 channel->fOutput.destination = media_destination::null; 800 channel->fOutput.format = channel->fPreferredFormat; 801 return; 802 } 803 804 // Okay, the connection has been confirmed. Record the destination and 805 // format that we agreed on, and report our connection name again. 806 channel->fOutput.destination = destination; 807 channel->fOutput.format = format; 808 #ifdef __HAIKU__ 809 strlcpy(name, channel->fOutput.name, B_MEDIA_NAME_LENGTH); 810 #else 811 strncpy(name, channel->fOutput.name, B_MEDIA_NAME_LENGTH); 812 #endif 813 814 // reset our buffer duration, etc. to avoid later calculations 815 bigtime_t duration = channel->fOutput.format.u.raw_audio.buffer_size * 10000 816 / ((channel->fOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) 817 * channel->fOutput.format.u.raw_audio.channel_count) 818 / ((int32)(channel->fOutput.format.u.raw_audio.frame_rate / 100)); 819 820 SetBufferDuration(duration); 821 822 // Now that we're connected, we can determine our downstream latency. 823 // Do so, then make sure we get our events early enough. 824 media_node_id id; 825 FindLatencyFor(channel->fOutput.destination, &fLatency, &id); 826 PRINT(("\tdownstream latency = %Ld\n", fLatency)); 827 828 fInternalLatency = BufferDuration(); 829 PRINT(("\tbuffer-filling took %Ld usec on this machine\n", fInternalLatency)); 830 //SetEventLatency(fLatency + fInternalLatency); 831 832 // Set up the buffer group for our connection, as long as nobody handed us 833 // a buffer group (via SetBufferGroup()) prior to this. That can happen, 834 // for example, if the consumer calls SetOutputBuffersFor() on us from 835 // within its Connected() method. 836 if (!channel->fBufferGroup) 837 _AllocateBuffers(*channel); 838 839 // we are sure the thread is started 840 _StartThread(); 841 } 842 843 844 void 845 MultiAudioNode::Disconnect(const media_source& what, 846 const media_destination& where) 847 { 848 CALLED(); 849 850 // is this our output? 851 node_output* channel = _FindOutput(what); 852 if (channel == NULL) { 853 fprintf(stderr, "MultiAudioNode::Disconnect() returning (cause : B_MEDIA_BAD_SOURCE)\n"); 854 return; 855 } 856 857 // Make sure that our connection is the one being disconnected 858 if (where == channel->fOutput.destination 859 && what == channel->fOutput.source) { 860 channel->fOutput.destination = media_destination::null; 861 channel->fOutput.format = channel->fPreferredFormat; 862 delete channel->fBufferGroup; 863 channel->fBufferGroup = NULL; 864 } else { 865 fprintf(stderr, "\tDisconnect() called with wrong source/destination (%ld/%ld), ours is (%ld/%ld)\n", 866 what.id, where.id, channel->fOutput.source.id, channel->fOutput.destination.id); 867 } 868 } 869 870 871 void 872 MultiAudioNode::LateNoticeReceived(const media_source& what, bigtime_t howMuch, 873 bigtime_t performanceTime) 874 { 875 CALLED(); 876 877 // is this our output? 878 node_output *channel = _FindOutput(what); 879 if (channel == NULL) 880 return; 881 882 // If we're late, we need to catch up. Respond in a manner appropriate 883 // to our current run mode. 884 if (RunMode() == B_RECORDING) { 885 // A hardware capture node can't adjust; it simply emits buffers at 886 // appropriate points. We (partially) simulate this by not adjusting 887 // our behavior upon receiving late notices -- after all, the hardware 888 // can't choose to capture "sooner".... 889 } else if (RunMode() == B_INCREASE_LATENCY) { 890 // We're late, and our run mode dictates that we try to produce buffers 891 // earlier in order to catch up. This argues that the downstream nodes 892 // are not properly reporting their latency, but there's not much we can 893 // do about that at the moment, so we try to start producing buffers 894 // earlier to compensate. 895 fInternalLatency += howMuch; 896 SetEventLatency(fLatency + fInternalLatency); 897 898 fprintf(stderr, "\tincreasing latency to %Ld\n", 899 fLatency + fInternalLatency); 900 } else { 901 // The other run modes dictate various strategies for sacrificing data 902 // quality in the interests of timely data delivery. The way *we* do 903 // this is to skip a buffer, which catches us up in time by one buffer 904 // duration. 905 /*size_t nSamples = fOutput.format.u.raw_audio.buffer_size / sizeof(float); 906 mSamplesSent += nSamples;*/ 907 908 fprintf(stderr, "\tskipping a buffer to try to catch up\n"); 909 } 910 } 911 912 913 void 914 MultiAudioNode::EnableOutput(const media_source& what, bool enabled, 915 int32* _deprecated_) 916 { 917 CALLED(); 918 919 // If I had more than one output, I'd have to walk my list of output 920 // records to see which one matched the given source, and then 921 // enable/disable that one. But this node only has one output, so I 922 // just make sure the given source matches, then set the enable state 923 // accordingly. 924 node_output *channel = _FindOutput(what); 925 if (channel != NULL) 926 channel->fOutputEnabled = enabled; 927 } 928 929 930 void 931 MultiAudioNode::AdditionalBufferRequested(const media_source& source, 932 media_buffer_id previousBuffer, bigtime_t previousTime, 933 const media_seek_tag* previousTag) 934 { 935 CALLED(); 936 // we don't support offline mode 937 return; 938 } 939 940 941 // #pragma mark - BMediaEventLooper 942 943 944 void 945 MultiAudioNode::HandleEvent(const media_timed_event* event, bigtime_t lateness, 946 bool realTimeEvent) 947 { 948 //CALLED(); 949 switch (event->type) { 950 case BTimedEventQueue::B_START: 951 _HandleStart(event, lateness, realTimeEvent); 952 break; 953 case BTimedEventQueue::B_SEEK: 954 _HandleSeek(event, lateness, realTimeEvent); 955 break; 956 case BTimedEventQueue::B_WARP: 957 _HandleWarp(event, lateness, realTimeEvent); 958 break; 959 case BTimedEventQueue::B_STOP: 960 _HandleStop(event, lateness, realTimeEvent); 961 break; 962 case BTimedEventQueue::B_HANDLE_BUFFER: 963 if (RunState() == BMediaEventLooper::B_STARTED) 964 _HandleBuffer(event, lateness, realTimeEvent); 965 break; 966 case BTimedEventQueue::B_DATA_STATUS: 967 _HandleDataStatus(event, lateness, realTimeEvent); 968 break; 969 case BTimedEventQueue::B_PARAMETER: 970 _HandleParameter(event, lateness, realTimeEvent); 971 break; 972 default: 973 fprintf(stderr," unknown event type: %li\n", event->type); 974 break; 975 } 976 } 977 978 979 // TODO: how should we handle late buffers? drop them? 980 // notify the producer? 981 status_t 982 MultiAudioNode::_HandleBuffer(const media_timed_event* event, 983 bigtime_t lateness, bool realTimeEvent) 984 { 985 //CALLED(); 986 BBuffer* buffer = const_cast<BBuffer*>((BBuffer*)event->pointer); 987 if (buffer == NULL) 988 return B_BAD_VALUE; 989 990 //PRINT(("buffer->Header()->destination : %i\n", buffer->Header()->destination)); 991 992 node_input* channel = _FindInput(buffer->Header()->destination); 993 if (channel == NULL) 994 return B_MEDIA_BAD_DESTINATION; 995 996 bigtime_t now = TimeSource()->Now(); 997 bigtime_t performanceTime = buffer->Header()->start_time; 998 999 // the how_early calculate here doesn't include scheduling latency because 1000 // we've already been scheduled to handle the buffer 1001 bigtime_t howEarly = performanceTime - EventLatency() - now; 1002 1003 // if the buffer is late, we ignore it and report the fact to the producer 1004 // who sent it to us 1005 if (RunMode() != B_OFFLINE && RunMode() != B_RECORDING && howEarly < 0LL) { 1006 // lateness doesn't matter in offline mode or in recording mode 1007 //mLateBuffers++; 1008 NotifyLateProducer(channel->fInput.source, -howEarly, performanceTime); 1009 fprintf(stderr," <- LATE BUFFER : %lli\n", howEarly); 1010 buffer->Recycle(); 1011 } else { 1012 //WriteBuffer(buffer, *channel); 1013 if (channel->fBuffer != NULL) { 1014 PRINT(("MultiAudioNode::HandleBuffer snoozing recycling channelId : %i, how_early:%lli\n", channel->fChannelId, how_early)); 1015 //channel->fBuffer->Recycle(); 1016 snooze(100); 1017 if (channel->fBuffer != NULL) 1018 buffer->Recycle(); 1019 else 1020 channel->fBuffer = buffer; 1021 } else { 1022 //PRINT(("MultiAudioNode::HandleBuffer writing channelId : %i, how_early:%lli\n", channel->fChannelId, how_early)); 1023 channel->fBuffer = buffer; 1024 } 1025 } 1026 return B_OK; 1027 } 1028 1029 1030 status_t 1031 MultiAudioNode::_HandleDataStatus(const media_timed_event* event, 1032 bigtime_t lateness, bool realTimeEvent) 1033 { 1034 //CALLED(); 1035 PRINT(("MultiAudioNode::HandleDataStatus status:%li, lateness:%li\n", event->data, lateness)); 1036 switch (event->data) { 1037 case B_DATA_NOT_AVAILABLE: 1038 break; 1039 case B_DATA_AVAILABLE: 1040 break; 1041 case B_PRODUCER_STOPPED: 1042 break; 1043 default: 1044 break; 1045 } 1046 return B_OK; 1047 } 1048 1049 1050 status_t 1051 MultiAudioNode::_HandleStart(const media_timed_event *event, bigtime_t lateness, 1052 bool realTimeEvent) 1053 { 1054 CALLED(); 1055 if (RunState() != B_STARTED) { 1056 } 1057 return B_OK; 1058 } 1059 1060 1061 status_t 1062 MultiAudioNode::_HandleSeek(const media_timed_event* event, bigtime_t lateness, 1063 bool realTimeEvent) 1064 { 1065 CALLED(); 1066 PRINT(("MultiAudioNode::HandleSeek(t=%lld,d=%li,bd=%lld)\n", 1067 event->event_time,event->data,event->bigdata)); 1068 return B_OK; 1069 } 1070 1071 1072 status_t 1073 MultiAudioNode::_HandleWarp(const media_timed_event* event, bigtime_t lateness, 1074 bool realTimeEvent) 1075 { 1076 CALLED(); 1077 return B_OK; 1078 } 1079 1080 1081 status_t 1082 MultiAudioNode::_HandleStop(const media_timed_event* event, bigtime_t lateness, 1083 bool realTimeEvent) 1084 { 1085 CALLED(); 1086 // flush the queue so downstreamers don't get any more 1087 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, 1088 BTimedEventQueue::B_HANDLE_BUFFER); 1089 1090 //_StopThread(); 1091 return B_OK; 1092 } 1093 1094 1095 status_t 1096 MultiAudioNode::_HandleParameter(const media_timed_event* event, 1097 bigtime_t lateness, bool realTimeEvent) 1098 { 1099 CALLED(); 1100 return B_OK; 1101 } 1102 1103 1104 // #pragma mark - BTimeSource 1105 1106 1107 void 1108 MultiAudioNode::SetRunMode(run_mode mode) 1109 { 1110 CALLED(); 1111 PRINT(("MultiAudioNode::SetRunMode mode:%i\n", mode)); 1112 //BTimeSource::SetRunMode(mode); 1113 } 1114 1115 1116 status_t 1117 MultiAudioNode::TimeSourceOp(const time_source_op_info& op, void* _reserved) 1118 { 1119 CALLED(); 1120 switch (op.op) { 1121 case B_TIMESOURCE_START: 1122 PRINT(("TimeSourceOp op B_TIMESOURCE_START\n")); 1123 if (RunState() != BMediaEventLooper::B_STARTED) { 1124 fTimeSourceStarted = true; 1125 _StartThread(); 1126 1127 media_timed_event startEvent(0, BTimedEventQueue::B_START); 1128 EventQueue()->AddEvent(startEvent); 1129 } 1130 break; 1131 case B_TIMESOURCE_STOP: 1132 PRINT(("TimeSourceOp op B_TIMESOURCE_STOP\n")); 1133 if (RunState() == BMediaEventLooper::B_STARTED) { 1134 media_timed_event stopEvent(0, BTimedEventQueue::B_STOP); 1135 EventQueue()->AddEvent(stopEvent); 1136 fTimeSourceStarted = false; 1137 _StopThread(); 1138 PublishTime(0, 0, 0); 1139 } 1140 break; 1141 case B_TIMESOURCE_STOP_IMMEDIATELY: 1142 PRINT(("TimeSourceOp op B_TIMESOURCE_STOP_IMMEDIATELY\n")); 1143 if (RunState() == BMediaEventLooper::B_STARTED) { 1144 media_timed_event stopEvent(0, BTimedEventQueue::B_STOP); 1145 EventQueue()->AddEvent(stopEvent); 1146 fTimeSourceStarted = false; 1147 _StopThread(); 1148 PublishTime(0, 0, 0); 1149 } 1150 break; 1151 case B_TIMESOURCE_SEEK: 1152 PRINT(("TimeSourceOp op B_TIMESOURCE_SEEK\n")); 1153 BroadcastTimeWarp(op.real_time, op.performance_time); 1154 break; 1155 default: 1156 break; 1157 } 1158 return B_OK; 1159 } 1160 1161 1162 // #pragma mark - BControllable 1163 1164 1165 status_t 1166 MultiAudioNode::GetParameterValue(int32 id, bigtime_t* lastChange, void* value, 1167 size_t* size) 1168 { 1169 CALLED(); 1170 1171 PRINT(("id : %i\n", id)); 1172 BParameter* parameter = NULL; 1173 for (int32 i = 0; i < fWeb->CountParameters(); i++) { 1174 parameter = fWeb->ParameterAt(i); 1175 if (parameter->ID() == id) 1176 break; 1177 } 1178 1179 if (parameter == NULL) { 1180 // Hmmm, we were asked for a parameter that we don't actually 1181 // support. Report an error back to the caller. 1182 PRINT(("\terror - asked for illegal parameter %ld\n", id)); 1183 return B_ERROR; 1184 } 1185 1186 multi_mix_value_info info; 1187 multi_mix_value values[2]; 1188 info.values = values; 1189 info.item_count = 0; 1190 1191 id = id - 100; 1192 1193 if (*size < sizeof(float)) 1194 return B_ERROR; 1195 1196 if (parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) { 1197 info.item_count = 1; 1198 values[0].id = id; 1199 1200 if (parameter->CountChannels() == 2) { 1201 if (*size < 2*sizeof(float)) 1202 return B_ERROR; 1203 info.item_count = 2; 1204 values[1].id = id + 1; 1205 } 1206 } else if(parameter->Type() == BParameter::B_DISCRETE_PARAMETER) { 1207 info.item_count = 1; 1208 values[0].id = id; 1209 } 1210 1211 if (info.item_count > 0) { 1212 status_t status = fDevice->GetMix(&info); 1213 if (status != B_OK) { 1214 fprintf(stderr, "Failed on DRIVER_GET_MIX\n"); 1215 } else { 1216 if (parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) { 1217 ((float*)value)[0] = values[0].gain; 1218 *size = sizeof(float); 1219 1220 if (parameter->CountChannels() == 2) { 1221 ((float*)value)[1] = values[1].gain; 1222 *size = 2*sizeof(float); 1223 } 1224 1225 for (uint32 i = 0; i < *size / sizeof(float); i++) { 1226 PRINT(("GetParameterValue B_CONTINUOUS_PARAMETER value[%i] : %f\n", i, ((float*)value)[i])); 1227 } 1228 } else if (parameter->Type() == BParameter::B_DISCRETE_PARAMETER) { 1229 BDiscreteParameter* discrete = (BDiscreteParameter*)parameter; 1230 if (discrete->CountItems() <= 2) 1231 ((int32*)value)[0] = values[0].enable ? 1 : 0; 1232 else 1233 ((int32*)value)[0] = values[0].mux; 1234 1235 *size = sizeof(int32); 1236 1237 for (uint32 i = 0; i < *size / sizeof(int32); i++) { 1238 PRINT(("GetParameterValue B_DISCRETE_PARAMETER value[%i] : %i\n", i, ((int32*)value)[i])); 1239 } 1240 } 1241 } 1242 } 1243 return B_OK; 1244 } 1245 1246 1247 void 1248 MultiAudioNode::SetParameterValue(int32 id, bigtime_t performanceTime, 1249 const void* value, size_t size) 1250 { 1251 CALLED(); 1252 PRINT(("id : %i, performance_time : %lld, size : %i\n", id, performanceTime, size)); 1253 1254 BParameter* parameter = NULL; 1255 for (int32 i = 0; i < fWeb->CountParameters(); i++) { 1256 parameter = fWeb->ParameterAt(i); 1257 if (parameter->ID() == id) 1258 break; 1259 } 1260 1261 if (parameter == NULL) 1262 return; 1263 1264 multi_mix_value_info info; 1265 multi_mix_value values[2]; 1266 info.values = values; 1267 info.item_count = 0; 1268 1269 id = id - 100; 1270 1271 if (parameter->Type() == BParameter::B_CONTINUOUS_PARAMETER) { 1272 for (uint32 i = 0; i < size / sizeof(float); i++) { 1273 PRINT(("SetParameterValue B_CONTINUOUS_PARAMETER value[%i] : %f\n", i, ((float*)value)[i])); 1274 } 1275 info.item_count = 1; 1276 values[0].id = id; 1277 values[0].gain = ((float*)value)[0]; 1278 1279 if (parameter->CountChannels() == 2) { 1280 info.item_count = 2; 1281 values[1].id = id + 1; 1282 values[1].gain = ((float*)value)[1]; 1283 } 1284 } else if (parameter->Type() == BParameter::B_DISCRETE_PARAMETER) { 1285 for (uint32 i = 0; i < size / sizeof(int32); i++) { 1286 PRINT(("SetParameterValue B_DISCRETE_PARAMETER value[%i] : %i\n", i, ((int32*)value)[i])); 1287 } 1288 1289 BDiscreteParameter* discrete = (BDiscreteParameter*)parameter; 1290 if (discrete->CountItems() <= 2) { 1291 info.item_count = 1; 1292 values[0].id = id; 1293 values[0].enable = ((int32*)value)[0] == 1; 1294 } else { 1295 info.item_count = 1; 1296 values[0].id = id; 1297 values[0].mux = ((uint32*)value)[0]; 1298 } 1299 } 1300 1301 if (info.item_count > 0) { 1302 status_t status = fDevice->SetMix(&info); 1303 if (status != B_OK) 1304 fprintf(stderr, "Failed on DRIVER_SET_MIX\n"); 1305 } 1306 } 1307 1308 1309 BParameterWeb* 1310 MultiAudioNode::MakeParameterWeb() 1311 { 1312 CALLED(); 1313 BParameterWeb* web = new BParameterWeb; 1314 1315 PRINT(("MixControlInfo().control_count : %i\n", 1316 fDevice->MixControlInfo().control_count)); 1317 1318 multi_mix_control* controls = fDevice->MixControlInfo().controls; 1319 1320 for (int i = 0; i < fDevice->MixControlInfo().control_count; i++) { 1321 if (controls[i].flags & B_MULTI_MIX_GROUP && controls[i].parent == 0) { 1322 PRINT(("NEW_GROUP\n")); 1323 BParameterGroup* child = web->MakeGroup( 1324 _GetControlName(controls[i])); 1325 1326 int32 numParameters = 0; 1327 _ProcessGroup(child, i, numParameters); 1328 } 1329 } 1330 1331 return web; 1332 } 1333 1334 1335 const char* 1336 MultiAudioNode::_GetControlName(multi_mix_control& control) 1337 { 1338 if (control.string != S_null) 1339 return kMultiControlString[control.string]; 1340 1341 return control.name; 1342 } 1343 1344 1345 void 1346 MultiAudioNode::_ProcessGroup(BParameterGroup* group, int32 index, 1347 int32& numParameters) 1348 { 1349 CALLED(); 1350 multi_mix_control* parent = &fDevice->MixControlInfo().controls[index]; 1351 multi_mix_control* controls = fDevice->MixControlInfo().controls; 1352 1353 for (int32 i = 0; i < fDevice->MixControlInfo().control_count; i++) { 1354 if (controls[i].parent != parent->id) 1355 continue; 1356 1357 const char* name = _GetControlName(controls[i]); 1358 1359 if (controls[i].flags & B_MULTI_MIX_GROUP) { 1360 PRINT(("NEW_GROUP\n")); 1361 BParameterGroup* child = group->MakeGroup(name); 1362 child->MakeNullParameter(controls[i].id, B_MEDIA_RAW_AUDIO, name, 1363 B_WEB_BUFFER_OUTPUT); 1364 1365 int32 num = 1; 1366 _ProcessGroup(child, i, num); 1367 } else if (controls[i].flags & B_MULTI_MIX_MUX) { 1368 PRINT(("NEW_MUX\n")); 1369 BDiscreteParameter* parameter = group->MakeDiscreteParameter( 1370 100 + controls[i].id, B_MEDIA_RAW_AUDIO, name, B_INPUT_MUX); 1371 if (numParameters > 0) { 1372 (group->ParameterAt(numParameters - 1))->AddOutput( 1373 group->ParameterAt(numParameters)); 1374 numParameters++; 1375 } 1376 _ProcessMux(parameter, i); 1377 } else if (controls[i].flags & B_MULTI_MIX_GAIN) { 1378 PRINT(("NEW_GAIN\n")); 1379 group->MakeContinuousParameter(100 + controls[i].id, 1380 B_MEDIA_RAW_AUDIO, "", B_MASTER_GAIN, "dB", 1381 controls[i].gain.min_gain, controls[i].gain.max_gain, 1382 controls[i].gain.granularity); 1383 1384 if (i + 1 < fDevice->MixControlInfo().control_count 1385 && controls[i + 1].master == controls[i].id 1386 && controls[i + 1].flags & B_MULTI_MIX_GAIN) { 1387 group->ParameterAt(numParameters)->SetChannelCount( 1388 group->ParameterAt(numParameters)->CountChannels() + 1); 1389 i++; 1390 } 1391 1392 PRINT(("num parameters : %d\n", numParameters)); 1393 if (numParameters > 0) { 1394 (group->ParameterAt(numParameters - 1))->AddOutput( 1395 group->ParameterAt(numParameters)); 1396 numParameters++; 1397 } 1398 } else if (controls[i].flags & B_MULTI_MIX_ENABLE) { 1399 PRINT(("NEW_ENABLE\n")); 1400 if (controls[i].string == S_MUTE) { 1401 group->MakeDiscreteParameter(100 + controls[i].id, 1402 B_MEDIA_RAW_AUDIO, name, B_MUTE); 1403 } else { 1404 group->MakeDiscreteParameter(100 + controls[i].id, 1405 B_MEDIA_RAW_AUDIO, name, B_ENABLE); 1406 } 1407 if (numParameters > 0) { 1408 (group->ParameterAt(numParameters - 1))->AddOutput( 1409 group->ParameterAt(numParameters)); 1410 numParameters++; 1411 } 1412 } 1413 } 1414 } 1415 1416 1417 void 1418 MultiAudioNode::_ProcessMux(BDiscreteParameter* parameter, int32 index) 1419 { 1420 CALLED(); 1421 multi_mix_control* parent = &fDevice->MixControlInfo().controls[index]; 1422 multi_mix_control* controls = fDevice->MixControlInfo().controls; 1423 int32 itemIndex = 0; 1424 1425 for (int32 i = 0; i < fDevice->MixControlInfo().control_count; i++) { 1426 if (controls[i].parent != parent->id) 1427 continue; 1428 1429 if (controls[i].flags & B_MULTI_MIX_MUX_VALUE) { 1430 PRINT(("NEW_MUX_VALUE\n")); 1431 parameter->AddItem(itemIndex, _GetControlName(controls[i])); 1432 itemIndex++; 1433 } 1434 } 1435 } 1436 1437 1438 // #pragma mark - MultiAudioNode specific functions 1439 1440 1441 int32 1442 MultiAudioNode::_RunThread() 1443 { 1444 CALLED(); 1445 multi_buffer_info bufferInfo; 1446 bufferInfo.info_size = sizeof(multi_buffer_info); 1447 bufferInfo._reserved_0 = 0; 1448 bufferInfo._reserved_1 = 2; 1449 bufferInfo.playback_buffer_cycle = 0; 1450 bufferInfo.record_buffer_cycle = 0; 1451 1452 while (true) { 1453 // TODO: why this semaphore?? 1454 if (acquire_sem_etc(fBufferFreeSem, 1, B_RELATIVE_TIMEOUT, 0) 1455 == B_BAD_SEM_ID) 1456 return B_OK; 1457 1458 // send buffer 1459 fDevice->BufferExchange(&bufferInfo); 1460 1461 //PRINT(("MultiAudioNode::RunThread: buffer exchanged\n")); 1462 //PRINT(("MultiAudioNode::RunThread: played_real_time : %i\n", bufferInfo.played_real_time)); 1463 //PRINT(("MultiAudioNode::RunThread: played_frames_count : %i\n", bufferInfo.played_frames_count)); 1464 //PRINT(("MultiAudioNode::RunThread: buffer_cycle : %i\n", bufferInfo.playback_buffer_cycle)); 1465 1466 for (int32 i = 0; i < fInputs.CountItems(); i++) { 1467 node_input* input = (node_input*)fInputs.ItemAt(i); 1468 1469 if (bufferInfo._reserved_0 == input->fChannelId 1470 && bufferInfo.playback_buffer_cycle >= 0 1471 && bufferInfo.playback_buffer_cycle 1472 < fDevice->BufferList().return_playback_buffers 1473 && (input->fOldBufferInfo.playback_buffer_cycle 1474 != bufferInfo.playback_buffer_cycle 1475 || fDevice->BufferList().return_playback_buffers == 1) 1476 && (input->fInput.source != media_source::null 1477 || input->fChannelId == 0)) { 1478 //PRINT(("playback_buffer_cycle ok input : %i %d\n", i, bufferInfo.playback_buffer_cycle)); 1479 1480 input->fBufferCycle = (bufferInfo.playback_buffer_cycle - 1 1481 + fDevice->BufferList().return_playback_buffers) 1482 % fDevice->BufferList().return_playback_buffers; 1483 1484 // update the timesource 1485 if (input->fChannelId == 0) { 1486 //PRINT(("updating timesource\n")); 1487 _UpdateTimeSource(bufferInfo, input->fOldBufferInfo, 1488 *input); 1489 } 1490 1491 input->fOldBufferInfo = bufferInfo; 1492 1493 if (input->fBuffer != NULL) { 1494 _FillNextBuffer(*input, input->fBuffer); 1495 input->fBuffer->Recycle(); 1496 input->fBuffer = NULL; 1497 } else { 1498 // put zeros in current buffer 1499 if (input->fInput.source != media_source::null) 1500 _WriteZeros(*input, input->fBufferCycle); 1501 //PRINT(("MultiAudioNode::Runthread WriteZeros\n")); 1502 } 1503 1504 // mark buffer free 1505 release_sem(fBufferFreeSem); 1506 } else { 1507 //PRINT(("playback_buffer_cycle non ok input : %i\n", i)); 1508 } 1509 } 1510 1511 for (int32 i = 0; i < fOutputs.CountItems(); i++) { 1512 node_output* output = (node_output*)fOutputs.ItemAt(i); 1513 1514 // make sure we're both started *and* connected before delivering a 1515 // buffer 1516 if (RunState() == BMediaEventLooper::B_STARTED 1517 && output->fOutput.destination != media_destination::null) { 1518 if (bufferInfo._reserved_1 == output->fChannelId 1519 && bufferInfo.record_buffer_cycle >= 0 1520 && bufferInfo.record_buffer_cycle 1521 < fDevice->BufferList().return_record_buffers 1522 && (output->fOldBufferInfo.record_buffer_cycle 1523 != bufferInfo.record_buffer_cycle 1524 || fDevice->BufferList().return_record_buffers == 1)) { 1525 //PRINT(("record_buffer_cycle ok\n")); 1526 1527 // Get the next buffer of data 1528 BBuffer* buffer = _FillNextBuffer(bufferInfo, *output); 1529 if (buffer != NULL) { 1530 // send the buffer downstream if and only if output is 1531 // enabled 1532 status_t err = B_ERROR; 1533 if (output->fOutputEnabled) { 1534 err = SendBuffer(buffer, 1535 output->fOutput.destination); 1536 } 1537 if (err) { 1538 buffer->Recycle(); 1539 } else { 1540 // track how much media we've delivered so far 1541 size_t numSamples 1542 = output->fOutput.format.u.raw_audio.buffer_size 1543 / (output->fOutput.format.u.raw_audio.format 1544 & media_raw_audio_format::B_AUDIO_SIZE_MASK); 1545 output->fSamplesSent += numSamples; 1546 } 1547 } 1548 1549 output->fOldBufferInfo = bufferInfo; 1550 } else { 1551 //PRINT(("record_buffer_cycle non ok\n")); 1552 } 1553 } 1554 } 1555 } 1556 1557 return B_OK; 1558 } 1559 1560 1561 void 1562 MultiAudioNode::_WriteZeros(node_input& input, uint32 bufferCycle) 1563 { 1564 //CALLED(); 1565 /*int32 samples = input.fInput.format.u.raw_audio.buffer_size; 1566 if(input.fInput.format.u.raw_audio.format == media_raw_audio_format::B_AUDIO_UCHAR) { 1567 uint8 *sample = (uint8*)fDevice->BufferList().playback_buffers[input.fBufferCycle][input.fChannelId].base; 1568 for(int32 i = samples-1; i>=0; i--) 1569 *sample++ = 128; 1570 } else { 1571 int32 *sample = (int32*)fDevice->BufferList().playback_buffers[input.fBufferCycle][input.fChannelId].base; 1572 for(int32 i = (samples / 4)-1; i>=0; i--) 1573 *sample++ = 0; 1574 }*/ 1575 1576 uint32 channelCount = input.fFormat.u.raw_audio.channel_count; 1577 uint32 bufferSize = fDevice->BufferList().return_playback_buffer_size; 1578 size_t stride = fDevice->BufferList().playback_buffers[bufferCycle] 1579 [input.fChannelId].stride; 1580 1581 switch (input.fFormat.u.raw_audio.format) { 1582 case media_raw_audio_format::B_AUDIO_FLOAT: 1583 for (uint32 channel = 0; channel < channelCount; channel++) { 1584 char* dest = _PlaybackBuffer(bufferCycle, 1585 input.fChannelId + channel); 1586 for (uint32 i = bufferSize; i > 0; i--) { 1587 *(float*)dest = 0; 1588 dest += stride; 1589 } 1590 } 1591 break; 1592 1593 case media_raw_audio_format::B_AUDIO_INT: 1594 for (uint32 channel = 0; channel < channelCount; channel++) { 1595 char* dest = _PlaybackBuffer(bufferCycle, 1596 input.fChannelId + channel); 1597 for (uint32 i = bufferSize; i > 0; i--) { 1598 *(int32*)dest = 0; 1599 dest += stride; 1600 } 1601 } 1602 break; 1603 1604 case media_raw_audio_format::B_AUDIO_SHORT: 1605 for (uint32 channel = 0; channel < channelCount; channel++) { 1606 char* dest = _PlaybackBuffer(bufferCycle, 1607 input.fChannelId + channel); 1608 for (uint32 i = bufferSize; i > 0; i--) { 1609 *(int16*)dest = 0; 1610 dest += stride; 1611 } 1612 } 1613 break; 1614 1615 default: 1616 fprintf(stderr, "ERROR in WriteZeros format not handled\n"); 1617 } 1618 } 1619 1620 1621 void 1622 MultiAudioNode::_FillWithZeros(node_input& input) 1623 { 1624 CALLED(); 1625 for (int32 i = 0; i < fDevice->BufferList().return_playback_buffers; i++) { 1626 _WriteZeros(input, i); 1627 } 1628 } 1629 1630 1631 void 1632 MultiAudioNode::_FillNextBuffer(node_input& input, BBuffer* buffer) 1633 { 1634 // TODO: simplify this, or put it into a static function to remove 1635 // the need for checking all over again 1636 1637 uint32 bufferSize = fDevice->BufferList().return_playback_buffer_size; 1638 1639 switch (input.fInput.format.u.raw_audio.format) { 1640 case media_raw_audio_format::B_AUDIO_FLOAT: 1641 switch (input.fFormat.u.raw_audio.format) { 1642 case media_raw_audio_format::B_AUDIO_FLOAT: 1643 { 1644 size_t frameSize = input.fInput.format.u.raw_audio 1645 .channel_count * sizeof(float); 1646 size_t stride = _PlaybackStride(input.fBufferCycle, 1647 input.fChannelId); 1648 //PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size)); 1649 for (uint32 channel = 0; channel 1650 < input.fInput.format.u.raw_audio.channel_count; 1651 channel++) { 1652 char* dest = _PlaybackBuffer(input.fBufferCycle, 1653 input.fChannelId + channel); 1654 char* src = (char*)buffer->Data() 1655 + channel * sizeof(float); 1656 1657 for (uint32 i = bufferSize; i > 0; i--) { 1658 *(float *)dest = *(float *)src; 1659 dest += stride; 1660 src += frameSize; 1661 } 1662 } 1663 break; 1664 } 1665 1666 case media_raw_audio_format::B_AUDIO_SHORT: 1667 if (input.fInput.format.u.raw_audio.channel_count == 2) { 1668 int16* dest1 = (int16*)_PlaybackBuffer( 1669 input.fBufferCycle, input.fChannelId); 1670 int16* dest2 = (int16*)_PlaybackBuffer( 1671 input.fBufferCycle, input.fChannelId + 1); 1672 float* src = (float*)buffer->Data(); 1673 if (_PlaybackStride(input.fBufferCycle, 1674 input.fChannelId) == sizeof(int16) 1675 && _PlaybackStride(input.fBufferCycle, 1676 input.fChannelId + 1) == sizeof(int16)) { 1677 //PRINT(("FillNextBuffer : 2 channels strides 2\n")); 1678 for (uint32 i = bufferSize; i > 0; i--) { 1679 *dest1++ = int16(32767 * *src++); 1680 *dest2++ = int16(32767 * *src++); 1681 } 1682 } else if (_PlaybackStride(input.fBufferCycle, 1683 input.fChannelId) == 2 * sizeof(int16) 1684 && _PlaybackStride(input.fBufferCycle, 1685 input.fChannelId + 1) == 2 * sizeof(int16) 1686 && dest1 + 1 == dest2) { 1687 //PRINT(("FillNextBuffer : 2 channels strides 4\n")); 1688 for (uint32 i = 2 * bufferSize; i > 0; i--) 1689 *dest1++ = int16(32767 * *src++); 1690 } else { 1691 //PRINT(("FillNextBuffer : 2 channels strides != 2\n")); 1692 size_t stride1 = _PlaybackStride(input.fBufferCycle, 1693 input.fChannelId) / sizeof(int16); 1694 size_t stride2 = _PlaybackStride(input.fBufferCycle, 1695 input.fChannelId + 1) / sizeof(int16); 1696 for (uint32 i = bufferSize; i > 0; i--) { 1697 *dest1 = int16(32767 * *src++); 1698 *dest2 = int16(32767 * *src++); 1699 dest1 += stride1; 1700 dest2 += stride2; 1701 } 1702 } 1703 } else { 1704 size_t frameSize = input.fInput.format.u 1705 .raw_audio.channel_count * sizeof(int16); 1706 size_t stride = _PlaybackStride(input.fBufferCycle, 1707 input.fChannelId); 1708 //PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size)); 1709 for (uint32 channel = 0; channel < 1710 input.fInput.format.u.raw_audio.channel_count; 1711 channel++) { 1712 char* dest = _PlaybackBuffer(input.fBufferCycle, 1713 input.fChannelId + channel); 1714 char* src = (char*)buffer->Data() 1715 + channel * sizeof(int16); 1716 1717 for (uint32 i = bufferSize; i > 0; i--) { 1718 *(int16*)dest = int16(32767 * *(float*)src); 1719 dest += stride; 1720 src += frameSize; 1721 } 1722 } 1723 } 1724 break; 1725 1726 case media_raw_audio_format::B_AUDIO_INT: 1727 default: 1728 break; 1729 } 1730 break; 1731 1732 case media_raw_audio_format::B_AUDIO_INT: 1733 switch (input.fFormat.u.raw_audio.format) { 1734 case media_raw_audio_format::B_AUDIO_INT: 1735 { 1736 size_t frameSize = input.fInput.format.u.raw_audio 1737 .channel_count * sizeof(int32); 1738 size_t stride = _PlaybackStride(input.fBufferCycle, 1739 input.fChannelId); 1740 //PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size)); 1741 for (uint32 channel = 0; channel 1742 < input.fInput.format.u.raw_audio.channel_count; 1743 channel++) { 1744 char* dest = _PlaybackBuffer(input.fBufferCycle, 1745 input.fChannelId + channel); 1746 char* src = (char*)buffer->Data() 1747 + channel * sizeof(int32); 1748 1749 for (uint32 i = bufferSize; i > 0; i--) { 1750 *(int32 *)dest = *(int32 *)src; 1751 dest += stride; 1752 src += frameSize; 1753 } 1754 } 1755 break; 1756 } 1757 case media_raw_audio_format::B_AUDIO_SHORT: 1758 case media_raw_audio_format::B_AUDIO_FLOAT: 1759 default: 1760 break; 1761 } 1762 break; 1763 1764 case media_raw_audio_format::B_AUDIO_SHORT: 1765 switch (input.fFormat.u.raw_audio.format) { 1766 case media_raw_audio_format::B_AUDIO_SHORT: 1767 if (input.fInput.format.u.raw_audio.channel_count == 2) { 1768 int16* dest1 = (int16*)_PlaybackBuffer( 1769 input.fBufferCycle, input.fChannelId); 1770 int16* dest2 = (int16*)_PlaybackBuffer( 1771 input.fBufferCycle, input.fChannelId + 1); 1772 int16* src = (int16*)buffer->Data(); 1773 if (_PlaybackStride(input.fBufferCycle, 1774 input.fChannelId) == sizeof(int16) 1775 && _PlaybackStride(input.fBufferCycle, 1776 input.fChannelId + 1) == sizeof(int16)) { 1777 //PRINT(("FillNextBuffer : 2 channels strides 2\n")); 1778 for (uint32 i = bufferSize; i > 0; i--) { 1779 *dest1++ = *src++; 1780 *dest2++ = *src++; 1781 } 1782 } else if (_PlaybackStride(input.fBufferCycle, 1783 input.fChannelId) == 2 * sizeof(int16) 1784 && _PlaybackStride(input.fBufferCycle, 1785 input.fChannelId + 1) == 2 * sizeof(int16) 1786 && dest1 + 1 == dest2) { 1787 //PRINT(("FillNextBuffer : 2 channels strides 4\n")); 1788 memcpy(dest1, src, 1789 bufferSize * 2 * sizeof(int16)); 1790 } else { 1791 //PRINT(("FillNextBuffer : 2 channels strides != 2\n")); 1792 size_t stride1 = _PlaybackStride( 1793 input.fBufferCycle, input.fChannelId) / 2; 1794 size_t stride2 = _PlaybackStride( 1795 input.fBufferCycle, input.fChannelId + 1) 1796 / 2; 1797 1798 for (uint32 i = bufferSize; i > 0; i--) { 1799 *dest1 = *src++; 1800 *dest2 = *src++; 1801 dest1 += stride1; 1802 dest2 += stride2; 1803 } 1804 } 1805 } else { 1806 size_t frameSize = input.fInput.format.u 1807 .raw_audio.channel_count * sizeof(int16); 1808 size_t stride = _PlaybackStride(input.fBufferCycle, 1809 input.fChannelId); 1810 //PRINT(("stride : %i, frame_size : %i, return_playback_buffer_size : %i\n", stride, frame_size, fDevice->BufferList().return_playback_buffer_size)); 1811 for (uint32 channel = 0; channel 1812 < input.fInput.format.u.raw_audio.channel_count; 1813 channel++) { 1814 char* dest = _PlaybackBuffer(input.fBufferCycle, 1815 input.fChannelId + channel); 1816 char* src = (char*)buffer->Data() 1817 + channel * sizeof(int16); 1818 1819 for (uint32 i = bufferSize; i > 0; i--) { 1820 *(int16*)dest = *(int16*)src; 1821 dest += stride; 1822 src += frameSize; 1823 } 1824 } 1825 } 1826 break; 1827 1828 case media_raw_audio_format::B_AUDIO_FLOAT: 1829 case media_raw_audio_format::B_AUDIO_INT: 1830 default: 1831 break; 1832 } 1833 break; 1834 1835 case media_raw_audio_format::B_AUDIO_UCHAR: 1836 default: 1837 break; 1838 } 1839 } 1840 1841 1842 status_t 1843 MultiAudioNode::_StartThread() 1844 { 1845 CALLED(); 1846 // the thread is already started ? 1847 if (fThread > B_OK) 1848 return B_OK; 1849 1850 // allocate buffer free semaphore 1851 fBufferFreeSem = create_sem( 1852 fDevice->BufferList().return_playback_buffers - 1, 1853 "multi_audio out buffer free"); 1854 if (fBufferFreeSem < B_OK) 1855 return fBufferFreeSem; 1856 1857 fThread = spawn_thread(_run_thread_, "multi_audio audio output", 1858 B_REAL_TIME_PRIORITY, this); 1859 if (fThread < B_OK) { 1860 delete_sem(fBufferFreeSem); 1861 return fThread; 1862 } 1863 1864 resume_thread(fThread); 1865 return B_OK; 1866 } 1867 1868 1869 status_t 1870 MultiAudioNode::_StopThread() 1871 { 1872 CALLED(); 1873 delete_sem(fBufferFreeSem); 1874 1875 wait_for_thread(fThread, &fThread); 1876 return B_OK; 1877 } 1878 1879 1880 void 1881 MultiAudioNode::_AllocateBuffers(node_output &channel) 1882 { 1883 CALLED(); 1884 1885 // allocate enough buffers to span our downstream latency, plus one 1886 size_t size = channel.fOutput.format.u.raw_audio.buffer_size; 1887 int32 count = int32(fLatency / BufferDuration() + 1 + 1); 1888 1889 PRINT(("\tlatency = %Ld, buffer duration = %Ld\n", fLatency, BufferDuration())); 1890 PRINT(("\tcreating group of %ld buffers, size = %lu\n", count, size)); 1891 channel.fBufferGroup = new BBufferGroup(size, count); 1892 } 1893 1894 1895 void 1896 MultiAudioNode::_UpdateTimeSource(multi_buffer_info& info, 1897 multi_buffer_info& oldInfo, node_input& input) 1898 { 1899 //CALLED(); 1900 if (!fTimeSourceStarted) 1901 return; 1902 1903 bigtime_t performanceTime = (bigtime_t)(info.played_frames_count / 1904 input.fInput.format.u.raw_audio.frame_rate * 1000000LL); 1905 bigtime_t realTime = info.played_real_time; 1906 float drift = ((info.played_frames_count - oldInfo.played_frames_count) 1907 / input.fInput.format.u.raw_audio.frame_rate * 1000000LL) 1908 / (info.played_real_time - oldInfo.played_real_time); 1909 1910 PublishTime(performanceTime, realTime, drift); 1911 //PRINT(("_UpdateTimeSource() perf_time : %lli, real_time : %lli, drift : %f\n", perf_time, real_time, drift)); 1912 } 1913 1914 1915 BBuffer* 1916 MultiAudioNode::_FillNextBuffer(multi_buffer_info &info, node_output &channel) 1917 { 1918 //CALLED(); 1919 // get a buffer from our buffer group 1920 //PRINT(("buffer size : %i, buffer duration : %i\n", fOutput.format.u.raw_audio.buffer_size, BufferDuration())); 1921 //PRINT(("MBI.record_buffer_cycle : %i\n", MBI.record_buffer_cycle)); 1922 //PRINT(("MBI.recorded_real_time : %i\n", MBI.recorded_real_time)); 1923 //PRINT(("MBI.recorded_frames_count : %i\n", MBI.recorded_frames_count)); 1924 if (!channel.fBufferGroup) 1925 return NULL; 1926 1927 BBuffer* buffer = channel.fBufferGroup->RequestBuffer( 1928 channel.fOutput.format.u.raw_audio.buffer_size, BufferDuration()); 1929 if (buffer == NULL) { 1930 // If we fail to get a buffer (for example, if the request times out), 1931 // we skip this buffer and go on to the next, to avoid locking up the 1932 // control thread. 1933 return NULL; 1934 } 1935 1936 if (fDevice == NULL) 1937 fprintf(stderr, "fDevice NULL\n"); 1938 if (buffer->Header() == NULL) 1939 fprintf(stderr, "buffer->Header() NULL\n"); 1940 if (TimeSource() == NULL) 1941 fprintf(stderr, "TimeSource() NULL\n"); 1942 1943 // now fill it with data, continuing where the last buffer left off 1944 memcpy(buffer->Data(), 1945 fDevice->BufferList().record_buffers[info.record_buffer_cycle] 1946 [channel.fChannelId - fDevice->Description().output_channel_count].base, 1947 channel.fOutput.format.u.raw_audio.buffer_size); 1948 1949 // fill in the buffer header 1950 media_header* header = buffer->Header(); 1951 header->type = B_MEDIA_RAW_AUDIO; 1952 header->size_used = channel.fOutput.format.u.raw_audio.buffer_size; 1953 header->time_source = TimeSource()->ID(); 1954 header->start_time = PerformanceTimeFor(info.recorded_real_time); 1955 1956 return buffer; 1957 } 1958 1959 1960 status_t 1961 MultiAudioNode::GetConfigurationFor(BMessage* message) 1962 { 1963 CALLED(); 1964 1965 BParameter *parameter = NULL; 1966 void *buffer; 1967 size_t bufferSize = 128; 1968 bigtime_t lastChange; 1969 status_t err; 1970 1971 if (message == NULL) 1972 return B_BAD_VALUE; 1973 1974 buffer = malloc(bufferSize); 1975 if (buffer == NULL) 1976 return B_NO_MEMORY; 1977 1978 for (int32 i = 0; i < fWeb->CountParameters(); i++) { 1979 parameter = fWeb->ParameterAt(i); 1980 if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER 1981 && parameter->Type() != BParameter::B_DISCRETE_PARAMETER) 1982 continue; 1983 1984 PRINT(("getting parameter %i\n", parameter->ID())); 1985 size_t size = bufferSize; 1986 while ((err = GetParameterValue(parameter->ID(), &lastChange, buffer, 1987 &size)) == B_NO_MEMORY && bufferSize < 128 * 1024) { 1988 bufferSize += 128; 1989 free(buffer); 1990 buffer = malloc(bufferSize); 1991 if (buffer == NULL) 1992 return B_NO_MEMORY; 1993 } 1994 1995 if (err == B_OK && size > 0) { 1996 message->AddInt32("parameterID", parameter->ID()); 1997 message->AddData("parameterData", B_RAW_TYPE, buffer, size, false); 1998 } else { 1999 PRINT(("parameter err : %s\n", strerror(err))); 2000 } 2001 } 2002 2003 free(buffer); 2004 PRINT_OBJECT(*message); 2005 return B_OK; 2006 } 2007 2008 2009 node_output* 2010 MultiAudioNode::_FindOutput(media_source source) 2011 { 2012 node_output* channel = NULL; 2013 2014 for (int32 i = 0; i < fOutputs.CountItems(); i++) { 2015 channel = (node_output*)fOutputs.ItemAt(i); 2016 if (source == channel->fOutput.source) 2017 break; 2018 } 2019 2020 if (source != channel->fOutput.source) 2021 return NULL; 2022 2023 return channel; 2024 } 2025 2026 2027 node_input* 2028 MultiAudioNode::_FindInput(media_destination dest) 2029 { 2030 node_input* channel = NULL; 2031 2032 for (int32 i = 0; i < fInputs.CountItems(); i++) { 2033 channel = (node_input*)fInputs.ItemAt(i); 2034 if (dest == channel->fInput.destination) 2035 break; 2036 } 2037 2038 if (dest != channel->fInput.destination) 2039 return NULL; 2040 2041 return channel; 2042 } 2043 2044 2045 node_input* 2046 MultiAudioNode::_FindInput(int32 destinationId) 2047 { 2048 node_input* channel = NULL; 2049 2050 for (int32 i = 0; i < fInputs.CountItems(); i++) { 2051 channel = (node_input*)fInputs.ItemAt(i); 2052 if (destinationId == channel->fInput.destination.id) 2053 break; 2054 } 2055 2056 if (destinationId != channel->fInput.destination.id) 2057 return NULL; 2058 2059 return channel; 2060 } 2061 2062 2063 /*static*/ status_t 2064 MultiAudioNode::_run_thread_(void* data) 2065 { 2066 CALLED(); 2067 return static_cast<MultiAudioNode*>(data)->_RunThread(); 2068 } 2069 2070 2071 void 2072 MultiAudioNode::GetFlavor(flavor_info* info, int32 id) 2073 { 2074 CALLED(); 2075 if (info == NULL) 2076 return; 2077 2078 info->flavor_flags = 0; 2079 info->possible_count = 1; // one flavor at a time 2080 info->in_format_count = 0; // no inputs 2081 info->in_formats = 0; 2082 info->out_format_count = 0; // no outputs 2083 info->out_formats = 0; 2084 info->internal_id = id; 2085 2086 info->name = "MultiAudioNode Node"; 2087 info->info = "The MultiAudioNode node outputs to multi_audio drivers."; 2088 info->kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER | B_TIME_SOURCE 2089 | B_PHYSICAL_OUTPUT | B_PHYSICAL_INPUT | B_CONTROLLABLE; 2090 info->in_format_count = 1; // 1 input 2091 media_format* inFormats = new media_format[info->in_format_count]; 2092 GetFormat(&inFormats[0]); 2093 info->in_formats = inFormats; 2094 2095 info->out_format_count = 1; // 1 output 2096 media_format* outFormats = new media_format[info->out_format_count]; 2097 GetFormat(&outFormats[0]); 2098 info->out_formats = outFormats; 2099 } 2100 2101 2102 void 2103 MultiAudioNode::GetFormat(media_format* format) 2104 { 2105 CALLED(); 2106 if (format == NULL) 2107 return; 2108 2109 format->type = B_MEDIA_RAW_AUDIO; 2110 format->require_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 2111 format->deny_flags = B_MEDIA_MAUI_UNDEFINED_FLAGS; 2112 format->u.raw_audio = media_raw_audio_format::wildcard; 2113 } 2114 2115