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