OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010, Google Inc. All rights reserved. | 2 * Copyright (C) 2010, Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 DCHECK_EQ(new_channel_count_mode_, channel_count_mode_); | 83 DCHECK_EQ(new_channel_count_mode_, channel_count_mode_); |
84 DCHECK_EQ(new_channel_interpretation_, channel_interpretation_); | 84 DCHECK_EQ(new_channel_interpretation_, channel_interpretation_); |
85 | 85 |
86 is_initialized_ = true; | 86 is_initialized_ = true; |
87 } | 87 } |
88 | 88 |
89 void AudioHandler::Uninitialize() { | 89 void AudioHandler::Uninitialize() { |
90 is_initialized_ = false; | 90 is_initialized_ = false; |
91 } | 91 } |
92 | 92 |
93 void AudioHandler::ClearInternalStateWhenDisabled() {} | |
94 | |
95 void AudioHandler::Dispose() { | 93 void AudioHandler::Dispose() { |
96 DCHECK(IsMainThread()); | 94 DCHECK(IsMainThread()); |
97 DCHECK(Context()->IsGraphOwner()); | 95 DCHECK(Context()->IsGraphOwner()); |
98 | 96 |
99 Context()->GetDeferredTaskHandler().RemoveChangedChannelCountMode(this); | 97 Context()->GetDeferredTaskHandler().RemoveChangedChannelCountMode(this); |
100 Context()->GetDeferredTaskHandler().RemoveChangedChannelInterpretation(this); | 98 Context()->GetDeferredTaskHandler().RemoveChangedChannelInterpretation(this); |
101 Context()->GetDeferredTaskHandler().RemoveAutomaticPullNode(this); | 99 Context()->GetDeferredTaskHandler().RemoveAutomaticPullNode(this); |
102 for (auto& output : outputs_) | 100 for (auto& output : outputs_) |
103 output->Dispose(); | 101 output->Dispose(); |
104 node_ = nullptr; | 102 node_ = nullptr; |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 // have the results cached in their bus; | 316 // have the results cached in their bus; |
319 double current_time = Context()->currentTime(); | 317 double current_time = Context()->currentTime(); |
320 if (last_processing_time_ != current_time) { | 318 if (last_processing_time_ != current_time) { |
321 // important to first update this time because of feedback loops in the | 319 // important to first update this time because of feedback loops in the |
322 // rendering graph. | 320 // rendering graph. |
323 last_processing_time_ = current_time; | 321 last_processing_time_ = current_time; |
324 | 322 |
325 PullInputs(frames_to_process); | 323 PullInputs(frames_to_process); |
326 | 324 |
327 bool silent_inputs = InputsAreSilent(); | 325 bool silent_inputs = InputsAreSilent(); |
328 if (!silent_inputs) { | |
329 last_non_silent_time_ = | |
330 (Context()->CurrentSampleFrame() + frames_to_process) / | |
331 static_cast<double>(Context()->sampleRate()); | |
332 } | |
333 | |
334 if (silent_inputs && PropagatesSilence()) { | 326 if (silent_inputs && PropagatesSilence()) { |
335 SilenceOutputs(); | 327 SilenceOutputs(); |
336 // AudioParams still need to be processed so that the value can be updated | 328 // AudioParams still need to be processed so that the value can be updated |
337 // if there are automations or so that the upstream nodes get pulled if | 329 // if there are automations or so that the upstream nodes get pulled if |
338 // any are connected to the AudioParam. | 330 // any are connected to the AudioParam. |
339 ProcessOnlyAudioParams(frames_to_process); | 331 ProcessOnlyAudioParams(frames_to_process); |
340 } else { | 332 } else { |
341 // Unsilence the outputs first because the processing of the node may | 333 // Unsilence the outputs first because the processing of the node may |
342 // cause the outputs to go silent and we want to propagate that hint to | 334 // cause the outputs to go silent and we want to propagate that hint to |
343 // the downstream nodes. (For example, a Gain node with a gain of 0 will | 335 // the downstream nodes. (For example, a Gain node with a gain of 0 will |
344 // want to silence its output.) | 336 // want to silence its output.) |
345 UnsilenceOutputs(); | 337 UnsilenceOutputs(); |
346 Process(frames_to_process); | 338 Process(frames_to_process); |
347 } | 339 } |
| 340 |
| 341 if (!silent_inputs) { |
| 342 // Update last_non_silent_time AFTER processing this block. |
| 343 // Doing it before causes PropagateSilence to be one render |
| 344 // quantum longer than necessary. |
| 345 last_non_silent_time_ = |
| 346 (Context()->CurrentSampleFrame() + frames_to_process) / |
| 347 static_cast<double>(Context()->sampleRate()); |
| 348 } |
348 } | 349 } |
349 } | 350 } |
350 | 351 |
351 void AudioHandler::CheckNumberOfChannelsForInput(AudioNodeInput* input) { | 352 void AudioHandler::CheckNumberOfChannelsForInput(AudioNodeInput* input) { |
352 DCHECK(Context()->IsAudioThread()); | 353 DCHECK(Context()->IsAudioThread()); |
353 DCHECK(Context()->IsGraphOwner()); | 354 DCHECK(Context()->IsGraphOwner()); |
354 | 355 |
355 DCHECK(inputs_.Contains(input)); | 356 DCHECK(inputs_.Contains(input)); |
356 if (!inputs_.Contains(input)) | 357 if (!inputs_.Contains(input)) |
357 return; | 358 return; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 DCHECK(IsMainThread()); | 396 DCHECK(IsMainThread()); |
396 BaseAudioContext::AutoLocker locker(Context()); | 397 BaseAudioContext::AutoLocker locker(Context()); |
397 | 398 |
398 is_disabled_ = false; | 399 is_disabled_ = false; |
399 for (auto& output : outputs_) | 400 for (auto& output : outputs_) |
400 output->Enable(); | 401 output->Enable(); |
401 } | 402 } |
402 } | 403 } |
403 | 404 |
404 void AudioHandler::DisableOutputsIfNecessary() { | 405 void AudioHandler::DisableOutputsIfNecessary() { |
| 406 // This function calls other functions that require graph ownership, |
| 407 // so assert that this needs graph ownership too. |
| 408 DCHECK(Context()->IsGraphOwner()); |
| 409 |
405 // Disable outputs if appropriate. We do this if the number of connections is | 410 // Disable outputs if appropriate. We do this if the number of connections is |
406 // 0 or 1. The case of 0 is from deref() where there are no connections left. | 411 // 0 or 1. The case of 0 is from deref() where there are no connections left. |
407 // The case of 1 is from AudioNodeInput::disable() where we want to disable | 412 // The case of 1 is from AudioNodeInput::disable() where we want to disable |
408 // outputs when there's only one connection left because we're ready to go | 413 // outputs when there's only one connection left because we're ready to go |
409 // away, but can't quite yet. | 414 // away, but can't quite yet. |
410 if (connection_ref_count_ <= 1 && !is_disabled_) { | 415 if (connection_ref_count_ <= 1 && !is_disabled_) { |
411 // Still may have JavaScript references, but no more "active" connection | 416 // Still may have JavaScript references, but no more "active" connection |
412 // references, so put all of our outputs in a "dormant" disabled state. | 417 // references, so put all of our outputs in a "dormant" disabled state. |
413 // Garbage collection may take a very long time after this time, so the | 418 // Garbage collection may take a very long time after this time, so the |
414 // "dormant" disabled nodes should not bog down the rendering... | 419 // "dormant" disabled nodes should not bog down the rendering... |
415 | 420 |
416 // As far as JavaScript is concerned, our outputs must still appear to be | 421 // As far as JavaScript is concerned, our outputs must still appear to be |
417 // connected. But internally our outputs should be disabled from the inputs | 422 // connected. But internally our outputs should be disabled from the inputs |
418 // they're connected to. disable() can recursively deref connections (and | 423 // they're connected to. disable() can recursively deref connections (and |
419 // call disable()) down a whole chain of connected nodes. | 424 // call disable()) down a whole chain of connected nodes. |
420 | 425 |
421 // TODO(rtoy,hongchan): we need special cases the convolver, delay, biquad, | 426 // If a node requires tail processing, we defer the disabling of |
422 // and IIR since they have a significant tail-time and shouldn't be | 427 // the outputs so that the tail for the node can be output. |
423 // disconnected simply because they no longer have any input connections. | 428 // Otherwise, we can disable the outputs right away. |
424 // This needs to be handled more generally where AudioNodes have a tailTime | 429 if (RequiresTailProcessing()) { |
425 // attribute. Then the AudioNode only needs to remain "active" for tailTime | 430 if (Context()->ContextState() != |
426 // seconds after there are no longer any active connections. | 431 BaseAudioContext::AudioContextState::kClosed) { |
427 // | 432 Context()->GetDeferredTaskHandler().AddTailProcessingNode(this); |
428 // The analyser node also requires special handling because we | 433 } |
429 // need the internal state to be updated for the time and FFT data | 434 } else { |
430 // even if it has no connections. | 435 ReallyDisableOutputs(); |
431 if (GetNodeType() != kNodeTypeConvolver && | |
432 GetNodeType() != kNodeTypeDelay && | |
433 GetNodeType() != kNodeTypeBiquadFilter && | |
434 GetNodeType() != kNodeTypeIIRFilter && | |
435 GetNodeType() != kNodeTypeAnalyser) { | |
436 is_disabled_ = true; | |
437 ClearInternalStateWhenDisabled(); | |
438 for (auto& output : outputs_) | |
439 output->Disable(); | |
440 } | 436 } |
441 } | 437 } |
442 } | 438 } |
443 | 439 |
| 440 void AudioHandler::ReallyDisableOutputs() { |
| 441 is_disabled_ = true; |
| 442 for (auto& output : outputs_) |
| 443 output->Disable(); |
| 444 } |
| 445 |
444 void AudioHandler::MakeConnection() { | 446 void AudioHandler::MakeConnection() { |
445 AtomicIncrement(&connection_ref_count_); | 447 AtomicIncrement(&connection_ref_count_); |
446 | 448 |
| 449 Context()->GetDeferredTaskHandler().RemoveTailProcessingNode(this); |
| 450 |
447 #if DEBUG_AUDIONODE_REFERENCES | 451 #if DEBUG_AUDIONODE_REFERENCES |
448 fprintf(stderr, "[%16p]: %16p: %2d: AudioHandler::ref %3d [%3d]\n", | 452 fprintf(stderr, "[%16p]: %16p: %2d: AudioHandler::ref %3d [%3d] @%.15g\n", |
449 Context(), this, GetNodeType(), connection_ref_count_, | 453 Context(), this, GetNodeType(), connection_ref_count_, |
450 node_count_[GetNodeType()]); | 454 node_count_[GetNodeType()], Context()->currentTime()); |
451 #endif | 455 #endif |
452 // See the disabling code in disableOutputsIfNecessary(). This handles | 456 // See the disabling code in disableOutputsIfNecessary(). This handles |
453 // the case where a node is being re-connected after being used at least | 457 // the case where a node is being re-connected after being used at least |
454 // once and disconnected. In this case, we need to re-enable. | 458 // once and disconnected. In this case, we need to re-enable. |
455 EnableOutputsIfNecessary(); | 459 EnableOutputsIfNecessary(); |
456 } | 460 } |
457 | 461 |
458 void AudioHandler::BreakConnection() { | 462 void AudioHandler::BreakConnection() { |
459 // The actual work for deref happens completely within the audio context's | 463 // The actual work for deref happens completely within the audio context's |
460 // graph lock. In the case of the audio thread, we must use a tryLock to | 464 // graph lock. In the case of the audio thread, we must use a tryLock to |
(...skipping 15 matching lines...) Expand all Loading... |
476 // later. | 480 // later. |
477 DCHECK(Context()->IsAudioThread()); | 481 DCHECK(Context()->IsAudioThread()); |
478 Context()->GetDeferredTaskHandler().AddDeferredBreakConnection(*this); | 482 Context()->GetDeferredTaskHandler().AddDeferredBreakConnection(*this); |
479 } | 483 } |
480 } | 484 } |
481 | 485 |
482 void AudioHandler::BreakConnectionWithLock() { | 486 void AudioHandler::BreakConnectionWithLock() { |
483 AtomicDecrement(&connection_ref_count_); | 487 AtomicDecrement(&connection_ref_count_); |
484 | 488 |
485 #if DEBUG_AUDIONODE_REFERENCES | 489 #if DEBUG_AUDIONODE_REFERENCES |
486 fprintf(stderr, "[%16p]: %16p: %2d: AudioHandler::deref %3d [%3d]\n", | 490 fprintf(stderr, "[%16p]: %16p: %2d: AudioHandler::deref %3d [%3d] @%.15g\n", |
487 Context(), this, GetNodeType(), connection_ref_count_, | 491 Context(), this, GetNodeType(), connection_ref_count_, |
488 node_count_[GetNodeType()]); | 492 node_count_[GetNodeType()], Context()->currentTime()); |
489 #endif | 493 #endif |
490 | 494 |
491 if (!connection_ref_count_) | 495 if (!connection_ref_count_) |
492 DisableOutputsIfNecessary(); | 496 DisableOutputsIfNecessary(); |
493 } | 497 } |
494 | 498 |
495 #if DEBUG_AUDIONODE_REFERENCES | 499 #if DEBUG_AUDIONODE_REFERENCES |
496 | 500 |
497 bool AudioHandler::is_node_count_initialized_ = false; | 501 bool AudioHandler::is_node_count_initialized_ = false; |
498 int AudioHandler::node_count_[kNodeTypeEnd]; | 502 int AudioHandler::node_count_[kNodeTypeEnd]; |
499 | 503 |
500 void AudioHandler::PrintNodeCounts() { | 504 void AudioHandler::PrintNodeCounts() { |
501 fprintf(stderr, "\n\n"); | 505 fprintf(stderr, "\n\n"); |
502 fprintf(stderr, "===========================\n"); | 506 fprintf(stderr, "===========================\n"); |
503 fprintf(stderr, "AudioNode: reference counts\n"); | 507 fprintf(stderr, "AudioNode: reference counts\n"); |
504 fprintf(stderr, "===========================\n"); | 508 fprintf(stderr, "===========================\n"); |
505 | 509 |
506 for (unsigned i = 0; i < kNodeTypeEnd; ++i) | 510 for (unsigned i = 0; i < kNodeTypeEnd; ++i) |
507 fprintf(stderr, "%2d: %d\n", i, node_count_[i]); | 511 fprintf(stderr, "%2d: %d\n", i, node_count_[i]); |
508 | 512 |
509 fprintf(stderr, "===========================\n\n\n"); | 513 fprintf(stderr, "===========================\n\n\n"); |
510 } | 514 } |
511 | 515 |
512 #endif // DEBUG_AUDIONODE_REFERENCES | 516 #endif // DEBUG_AUDIONODE_REFERENCES |
513 | 517 |
| 518 #if DEBUG_AUDIONODE_REFERENCES > 1 |
| 519 void AudioHandler::TailProcessingDebug(const char* note) { |
| 520 fprintf(stderr, "[%16p]: %16p: %2d: %s %d @%.15g", Context(), this, |
| 521 GetNodeType(), note, connection_ref_count_, Context()->currentTime()); |
| 522 |
| 523 // If we're on the audio thread, we can print out the tail and |
| 524 // latency times (because these methods can only be called from the |
| 525 // audio thread.) |
| 526 if (Context()->IsAudioThread()) { |
| 527 fprintf(stderr, ", tail=%.15g + %.15g, last=%.15g\n", TailTime(), |
| 528 LatencyTime(), last_non_silent_time_); |
| 529 } |
| 530 |
| 531 fprintf(stderr, "\n"); |
| 532 } |
| 533 |
| 534 void AudioHandler::AddTailProcessingDebug() { |
| 535 TailProcessingDebug("addTail"); |
| 536 } |
| 537 |
| 538 void AudioHandler::RemoveTailProcessingDebug() { |
| 539 TailProcessingDebug("remTail"); |
| 540 } |
| 541 #endif // DEBUG_AUDIONODE_REFERENCES > 1 |
| 542 |
514 void AudioHandler::UpdateChannelCountMode() { | 543 void AudioHandler::UpdateChannelCountMode() { |
515 channel_count_mode_ = new_channel_count_mode_; | 544 channel_count_mode_ = new_channel_count_mode_; |
516 UpdateChannelsForInputs(); | 545 UpdateChannelsForInputs(); |
517 } | 546 } |
518 | 547 |
519 void AudioHandler::UpdateChannelInterpretation() { | 548 void AudioHandler::UpdateChannelInterpretation() { |
520 channel_interpretation_ = new_channel_interpretation_; | 549 channel_interpretation_ = new_channel_interpretation_; |
521 } | 550 } |
522 | 551 |
523 unsigned AudioHandler::NumberOfOutputChannels() const { | 552 unsigned AudioHandler::NumberOfOutputChannels() const { |
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
961 } | 990 } |
962 | 991 |
963 void AudioNode::DidAddOutput(unsigned number_of_outputs) { | 992 void AudioNode::DidAddOutput(unsigned number_of_outputs) { |
964 connected_nodes_.push_back(nullptr); | 993 connected_nodes_.push_back(nullptr); |
965 DCHECK_EQ(number_of_outputs, connected_nodes_.size()); | 994 DCHECK_EQ(number_of_outputs, connected_nodes_.size()); |
966 connected_params_.push_back(nullptr); | 995 connected_params_.push_back(nullptr); |
967 DCHECK_EQ(number_of_outputs, connected_params_.size()); | 996 DCHECK_EQ(number_of_outputs, connected_params_.size()); |
968 } | 997 } |
969 | 998 |
970 } // namespace blink | 999 } // namespace blink |
OLD | NEW |