Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(210)

Side by Side Diff: media/audio/win/audio_low_latency_output_win.cc

Issue 27181005: Fail out of WASAPI render loop when errors are encountered. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix signature. Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/audio/win/audio_low_latency_output_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/win/audio_low_latency_output_win.h" 5 #include "media/audio/win/audio_low_latency_output_win.h"
6 6
7 #include <Functiondiscoverykeys_devpkey.h> 7 #include <Functiondiscoverykeys_devpkey.h>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event.h"
(...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after
465 FALSE, 465 FALSE,
466 INFINITE); 466 INFINITE);
467 467
468 switch (wait_result) { 468 switch (wait_result) {
469 case WAIT_OBJECT_0 + 0: 469 case WAIT_OBJECT_0 + 0:
470 // |stop_render_event_| has been set. 470 // |stop_render_event_| has been set.
471 playing = false; 471 playing = false;
472 break; 472 break;
473 case WAIT_OBJECT_0 + 1: 473 case WAIT_OBJECT_0 + 1:
474 // |audio_samples_render_event_| has been set. 474 // |audio_samples_render_event_| has been set.
475 RenderAudioFromSource(audio_clock, device_frequency); 475 error = !RenderAudioFromSource(audio_clock, device_frequency);
476 break; 476 break;
477 default: 477 default:
478 error = true; 478 error = true;
479 break; 479 break;
480 } 480 }
481 } 481 }
482 482
483 if (playing && error) { 483 if (playing && error) {
484 // Stop audio rendering since something has gone wrong in our main thread 484 // Stop audio rendering since something has gone wrong in our main thread
485 // loop. Note that, we are still in a "started" state, hence a Stop() call 485 // loop. Note that, we are still in a "started" state, hence a Stop() call
486 // is required to join the thread properly. 486 // is required to join the thread properly.
487 audio_client_->Stop(); 487 audio_client_->Stop();
488 PLOG(ERROR) << "WASAPI rendering failed."; 488 PLOG(ERROR) << "WASAPI rendering failed.";
489 } 489 }
490 490
491 // Disable MMCSS. 491 // Disable MMCSS.
492 if (mm_task && !avrt::AvRevertMmThreadCharacteristics(mm_task)) { 492 if (mm_task && !avrt::AvRevertMmThreadCharacteristics(mm_task)) {
493 PLOG(WARNING) << "Failed to disable MMCSS"; 493 PLOG(WARNING) << "Failed to disable MMCSS";
494 } 494 }
495 } 495 }
496 496
497 void WASAPIAudioOutputStream::RenderAudioFromSource( 497 bool WASAPIAudioOutputStream::RenderAudioFromSource(
498 IAudioClock* audio_clock, UINT64 device_frequency) { 498 IAudioClock* audio_clock, UINT64 device_frequency) {
499 TRACE_EVENT0("audio", "RenderAudioFromSource"); 499 TRACE_EVENT0("audio", "RenderAudioFromSource");
500 500
501 HRESULT hr = S_FALSE; 501 HRESULT hr = S_FALSE;
502 UINT32 num_queued_frames = 0; 502 UINT32 num_queued_frames = 0;
503 uint8* audio_data = NULL; 503 uint8* audio_data = NULL;
504 504
505 // Contains how much new data we can write to the buffer without 505 // Contains how much new data we can write to the buffer without
506 // the risk of overwriting previously written data that the audio 506 // the risk of overwriting previously written data that the audio
507 // engine has not yet read from the buffer. 507 // engine has not yet read from the buffer.
508 size_t num_available_frames = 0; 508 size_t num_available_frames = 0;
509 509
510 if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { 510 if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
511 // Get the padding value which represents the amount of rendering 511 // Get the padding value which represents the amount of rendering
512 // data that is queued up to play in the endpoint buffer. 512 // data that is queued up to play in the endpoint buffer.
513 hr = audio_client_->GetCurrentPadding(&num_queued_frames); 513 hr = audio_client_->GetCurrentPadding(&num_queued_frames);
514 num_available_frames = 514 num_available_frames =
515 endpoint_buffer_size_frames_ - num_queued_frames; 515 endpoint_buffer_size_frames_ - num_queued_frames;
516 if (FAILED(hr)) { 516 if (FAILED(hr)) {
517 DLOG(ERROR) << "Failed to retrieve amount of available space: " 517 DLOG(ERROR) << "Failed to retrieve amount of available space: "
518 << std::hex << hr; 518 << std::hex << hr;
519 return; 519 return false;
520 } 520 }
521 } else { 521 } else {
522 // While the stream is running, the system alternately sends one 522 // While the stream is running, the system alternately sends one
523 // buffer or the other to the client. This form of double buffering 523 // buffer or the other to the client. This form of double buffering
524 // is referred to as "ping-ponging". Each time the client receives 524 // is referred to as "ping-ponging". Each time the client receives
525 // a buffer from the system (triggers this event) the client must 525 // a buffer from the system (triggers this event) the client must
526 // process the entire buffer. Calls to the GetCurrentPadding method 526 // process the entire buffer. Calls to the GetCurrentPadding method
527 // are unnecessary because the packet size must always equal the 527 // are unnecessary because the packet size must always equal the
528 // buffer size. In contrast to the shared mode buffering scheme, 528 // buffer size. In contrast to the shared mode buffering scheme,
529 // the latency for an event-driven, exclusive-mode stream depends 529 // the latency for an event-driven, exclusive-mode stream depends
530 // directly on the buffer size. 530 // directly on the buffer size.
531 num_available_frames = endpoint_buffer_size_frames_; 531 num_available_frames = endpoint_buffer_size_frames_;
532 } 532 }
533 533
534 // Check if there is enough available space to fit the packet size 534 // Check if there is enough available space to fit the packet size
535 // specified by the client. 535 // specified by the client.
536 if (num_available_frames < packet_size_frames_) 536 if (num_available_frames < packet_size_frames_)
537 return; 537 return true;
538 538
539 DLOG_IF(ERROR, num_available_frames % packet_size_frames_ != 0) 539 DLOG_IF(ERROR, num_available_frames % packet_size_frames_ != 0)
540 << "Non-perfect timing detected (num_available_frames=" 540 << "Non-perfect timing detected (num_available_frames="
541 << num_available_frames << ", packet_size_frames=" 541 << num_available_frames << ", packet_size_frames="
542 << packet_size_frames_ << ")"; 542 << packet_size_frames_ << ")";
543 543
544 // Derive the number of packets we need to get from the client to 544 // Derive the number of packets we need to get from the client to
545 // fill up the available area in the endpoint buffer. 545 // fill up the available area in the endpoint buffer.
546 // |num_packets| will always be one for exclusive-mode streams and 546 // |num_packets| will always be one for exclusive-mode streams and
547 // will be one in most cases for shared mode streams as well. 547 // will be one in most cases for shared mode streams as well.
548 // However, we have found that two packets can sometimes be 548 // However, we have found that two packets can sometimes be
549 // required. 549 // required.
550 size_t num_packets = (num_available_frames / packet_size_frames_); 550 size_t num_packets = (num_available_frames / packet_size_frames_);
551 551
552 for (size_t n = 0; n < num_packets; ++n) { 552 for (size_t n = 0; n < num_packets; ++n) {
553 // Grab all available space in the rendering endpoint buffer 553 // Grab all available space in the rendering endpoint buffer
554 // into which the client can write a data packet. 554 // into which the client can write a data packet.
555 hr = audio_render_client_->GetBuffer(packet_size_frames_, 555 hr = audio_render_client_->GetBuffer(packet_size_frames_,
556 &audio_data); 556 &audio_data);
557 if (FAILED(hr)) { 557 if (FAILED(hr)) {
558 DLOG(ERROR) << "Failed to use rendering audio buffer: " 558 DLOG(ERROR) << "Failed to use rendering audio buffer: "
559 << std::hex << hr; 559 << std::hex << hr;
560 return; 560 return false;
561 } 561 }
562 562
563 // Derive the audio delay which corresponds to the delay between 563 // Derive the audio delay which corresponds to the delay between
564 // a render event and the time when the first audio sample in a 564 // a render event and the time when the first audio sample in a
565 // packet is played out through the speaker. This delay value 565 // packet is played out through the speaker. This delay value
566 // can typically be utilized by an acoustic echo-control (AEC) 566 // can typically be utilized by an acoustic echo-control (AEC)
567 // unit at the render side. 567 // unit at the render side.
568 UINT64 position = 0; 568 UINT64 position = 0;
569 int audio_delay_bytes = 0; 569 int audio_delay_bytes = 0;
570 hr = audio_clock->GetPosition(&position, NULL); 570 hr = audio_clock->GetPosition(&position, NULL);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
608 608
609 609
610 // Release the buffer space acquired in the GetBuffer() call. 610 // Release the buffer space acquired in the GetBuffer() call.
611 // Render silence if we were not able to fill up the buffer totally. 611 // Render silence if we were not able to fill up the buffer totally.
612 DWORD flags = (num_filled_bytes < packet_size_bytes_) ? 612 DWORD flags = (num_filled_bytes < packet_size_bytes_) ?
613 AUDCLNT_BUFFERFLAGS_SILENT : 0; 613 AUDCLNT_BUFFERFLAGS_SILENT : 0;
614 audio_render_client_->ReleaseBuffer(packet_size_frames_, flags); 614 audio_render_client_->ReleaseBuffer(packet_size_frames_, flags);
615 615
616 num_written_frames_ += packet_size_frames_; 616 num_written_frames_ += packet_size_frames_;
617 } 617 }
618
619 return true;
618 } 620 }
619 621
620 HRESULT WASAPIAudioOutputStream::ExclusiveModeInitialization( 622 HRESULT WASAPIAudioOutputStream::ExclusiveModeInitialization(
621 IAudioClient* client, HANDLE event_handle, uint32* endpoint_buffer_size) { 623 IAudioClient* client, HANDLE event_handle, uint32* endpoint_buffer_size) {
622 DCHECK_EQ(share_mode_, AUDCLNT_SHAREMODE_EXCLUSIVE); 624 DCHECK_EQ(share_mode_, AUDCLNT_SHAREMODE_EXCLUSIVE);
623 625
624 float f = (1000.0 * packet_size_frames_) / format_.Format.nSamplesPerSec; 626 float f = (1000.0 * packet_size_frames_) / format_.Format.nSamplesPerSec;
625 REFERENCE_TIME requested_buffer_duration = 627 REFERENCE_TIME requested_buffer_duration =
626 static_cast<REFERENCE_TIME>(f * 10000.0 + 0.5); 628 static_cast<REFERENCE_TIME>(f * 10000.0 + 0.5);
627 629
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
708 710
709 // Ensure that we don't quit the main thread loop immediately next 711 // Ensure that we don't quit the main thread loop immediately next
710 // time Start() is called. 712 // time Start() is called.
711 ResetEvent(stop_render_event_.Get()); 713 ResetEvent(stop_render_event_.Get());
712 } 714 }
713 715
714 source_ = NULL; 716 source_ = NULL;
715 } 717 }
716 718
717 } // namespace media 719 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/win/audio_low_latency_output_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698