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