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