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