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