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