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