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

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

Issue 1097553003: Switch to STA mode for audio thread and WASAPI I/O streams. (Closed) Base URL: http://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix test. Created 5 years, 8 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
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/logging.h" 10 #include "base/logging.h"
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 opened_(false), 63 opened_(false),
64 volume_(1.0), 64 volume_(1.0),
65 packet_size_frames_(0), 65 packet_size_frames_(0),
66 packet_size_bytes_(0), 66 packet_size_bytes_(0),
67 endpoint_buffer_size_frames_(0), 67 endpoint_buffer_size_frames_(0),
68 device_id_(device_id), 68 device_id_(device_id),
69 device_role_(device_role), 69 device_role_(device_role),
70 share_mode_(GetShareMode()), 70 share_mode_(GetShareMode()),
71 num_written_frames_(0), 71 num_written_frames_(0),
72 source_(NULL), 72 source_(NULL),
73 com_stream_(NULL),
73 audio_bus_(AudioBus::Create(params)) { 74 audio_bus_(AudioBus::Create(params)) {
74 DCHECK(manager_); 75 DCHECK(manager_);
75 76
76 DVLOG(1) << "WASAPIAudioOutputStream::WASAPIAudioOutputStream()"; 77 DVLOG(1) << "WASAPIAudioOutputStream::WASAPIAudioOutputStream()";
77 DVLOG_IF(1, share_mode_ == AUDCLNT_SHAREMODE_EXCLUSIVE) 78 DVLOG_IF(1, share_mode_ == AUDCLNT_SHAREMODE_EXCLUSIVE)
78 << "Core Audio (WASAPI) EXCLUSIVE MODE is enabled."; 79 << "Core Audio (WASAPI) EXCLUSIVE MODE is enabled.";
79 80
80 // Load the Avrt DLL if not already loaded. Required to support MMCSS. 81 // Load the Avrt DLL if not already loaded. Required to support MMCSS.
81 bool avrt_init = avrt::Initialize(); 82 bool avrt_init = avrt::Initialize();
82 DCHECK(avrt_init) << "Failed to load the avrt.dll"; 83 DCHECK(avrt_init) << "Failed to load the avrt.dll";
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { 248 if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
248 if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence( 249 if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence(
249 audio_client_.get(), audio_render_client_.get())) { 250 audio_client_.get(), audio_render_client_.get())) {
250 LOG(ERROR) << "Failed to prepare endpoint buffers with silence."; 251 LOG(ERROR) << "Failed to prepare endpoint buffers with silence.";
251 callback->OnError(this); 252 callback->OnError(this);
252 return; 253 return;
253 } 254 }
254 } 255 }
255 num_written_frames_ = endpoint_buffer_size_frames_; 256 num_written_frames_ = endpoint_buffer_size_frames_;
256 257
258 if (!MarshalComPointers()) {
259 callback->OnError(this);
260 return;
261 }
262
257 // Create and start the thread that will drive the rendering by waiting for 263 // Create and start the thread that will drive the rendering by waiting for
258 // render events. 264 // render events.
259 render_thread_.reset( 265 render_thread_.reset(
260 new base::DelegateSimpleThread(this, "wasapi_render_thread")); 266 new base::DelegateSimpleThread(this, "wasapi_render_thread"));
261 render_thread_->Start(); 267 render_thread_->Start();
262 if (!render_thread_->HasBeenStarted()) { 268 if (!render_thread_->HasBeenStarted()) {
263 LOG(ERROR) << "Failed to start WASAPI render thread."; 269 LOG(ERROR) << "Failed to start WASAPI render thread.";
264 StopThread(); 270 StopThread();
265 callback->OnError(this); 271 callback->OnError(this);
266 return; 272 return;
267 } 273 }
268 274
269 // Start streaming data between the endpoint buffer and the audio engine. 275 // Start streaming data between the endpoint buffer and the audio engine.
276 // TODO(dalecurtis): Do we need a lock on this with STA mode?
270 HRESULT hr = audio_client_->Start(); 277 HRESULT hr = audio_client_->Start();
271 if (FAILED(hr)) { 278 if (FAILED(hr)) {
272 PLOG(ERROR) << "Failed to start output streaming: " << std::hex << hr; 279 PLOG(ERROR) << "Failed to start output streaming: " << std::hex << hr;
273 StopThread(); 280 StopThread();
274 callback->OnError(this); 281 callback->OnError(this);
275 } 282 }
276 } 283 }
277 284
278 void WASAPIAudioOutputStream::Stop() { 285 void WASAPIAudioOutputStream::Stop() {
279 DVLOG(1) << "WASAPIAudioOutputStream::Stop()"; 286 DVLOG(1) << "WASAPIAudioOutputStream::Stop()";
280 DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); 287 DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_);
281 if (!render_thread_) 288 if (!render_thread_)
282 return; 289 return;
283 290
284 // Stop output audio streaming. 291 // Stop output audio streaming.
292 // TODO(dalecurtis): Do we need a lock on this with STA mode?
285 HRESULT hr = audio_client_->Stop(); 293 HRESULT hr = audio_client_->Stop();
286 if (FAILED(hr)) { 294 if (FAILED(hr)) {
287 PLOG(ERROR) << "Failed to stop output streaming: " << std::hex << hr; 295 PLOG(ERROR) << "Failed to stop output streaming: " << std::hex << hr;
288 source_->OnError(this); 296 source_->OnError(this);
289 } 297 }
290 298
291 // Make a local copy of |source_| since StopThread() will clear it. 299 // Make a local copy of |source_| since StopThread() will clear it.
292 AudioSourceCallback* callback = source_; 300 AudioSourceCallback* callback = source_;
293 StopThread(); 301 StopThread();
294 302
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 } 339 }
332 volume_ = volume_float; 340 volume_ = volume_float;
333 } 341 }
334 342
335 void WASAPIAudioOutputStream::GetVolume(double* volume) { 343 void WASAPIAudioOutputStream::GetVolume(double* volume) {
336 DVLOG(1) << "GetVolume()"; 344 DVLOG(1) << "GetVolume()";
337 *volume = static_cast<double>(volume_); 345 *volume = static_cast<double>(volume_);
338 } 346 }
339 347
340 void WASAPIAudioOutputStream::Run() { 348 void WASAPIAudioOutputStream::Run() {
341 ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA); 349 ScopedCOMInitializer com_init;
342 350
343 // Increase the thread priority. 351 // Increase the thread priority.
344 render_thread_->SetThreadPriority(base::ThreadPriority::REALTIME_AUDIO); 352 render_thread_->SetThreadPriority(base::ThreadPriority::REALTIME_AUDIO);
345 353
346 // Enable MMCSS to ensure that this thread receives prioritized access to 354 // Enable MMCSS to ensure that this thread receives prioritized access to
347 // CPU resources. 355 // CPU resources.
348 DWORD task_index = 0; 356 DWORD task_index = 0;
349 HANDLE mm_task = avrt::AvSetMmThreadCharacteristics(L"Pro Audio", 357 HANDLE mm_task = avrt::AvSetMmThreadCharacteristics(L"Pro Audio",
350 &task_index); 358 &task_index);
351 bool mmcss_is_ok = 359 bool mmcss_is_ok =
352 (mm_task && avrt::AvSetMmThreadPriority(mm_task, AVRT_PRIORITY_CRITICAL)); 360 (mm_task && avrt::AvSetMmThreadPriority(mm_task, AVRT_PRIORITY_CRITICAL));
353 if (!mmcss_is_ok) { 361 if (!mmcss_is_ok) {
354 // Failed to enable MMCSS on this thread. It is not fatal but can lead 362 // Failed to enable MMCSS on this thread. It is not fatal but can lead
355 // to reduced QoS at high load. 363 // to reduced QoS at high load.
356 DWORD err = GetLastError(); 364 DWORD err = GetLastError();
357 LOG(WARNING) << "Failed to enable MMCSS (error code=" << err << ")."; 365 LOG(WARNING) << "Failed to enable MMCSS (error code=" << err << ").";
358 } 366 }
359 367
368 // Retrieve COM pointers from the main thread.
369 IAudioClient* thread_audio_client = NULL;
370 IAudioRenderClient* thread_audio_render_client = NULL;
371 IAudioClock* thread_audio_clock = NULL;
372
360 HRESULT hr = S_FALSE; 373 HRESULT hr = S_FALSE;
361 374
362 bool playing = true; 375 bool playing = true;
363 bool error = false; 376 bool error =
377 !UnmarshalComPointers(&thread_audio_client, &thread_audio_render_client,
378 &thread_audio_clock);
379
364 HANDLE wait_array[] = { stop_render_event_.Get(), 380 HANDLE wait_array[] = { stop_render_event_.Get(),
365 audio_samples_render_event_.Get() }; 381 audio_samples_render_event_.Get() };
366 UINT64 device_frequency = 0; 382 UINT64 device_frequency = 0;
367 383
368 // The device frequency is the frequency generated by the hardware clock in 384 if (!error) {
369 // the audio device. The GetFrequency() method reports a constant frequency. 385 // The device frequency is the frequency generated by the hardware clock in
370 hr = audio_clock_->GetFrequency(&device_frequency); 386 // the audio device. The GetFrequency() method reports a constant frequency.
371 error = FAILED(hr); 387 hr = audio_clock_->GetFrequency(&device_frequency);
372 PLOG_IF(ERROR, error) << "Failed to acquire IAudioClock interface: " 388 error = FAILED(hr);
373 << std::hex << hr; 389 PLOG_IF(ERROR, error) << "Failed to acquire IAudioClock interface: "
390 << std::hex << hr;
391 }
374 392
375 // Keep rendering audio until the stop event or the stream-switch event 393 // Keep rendering audio until the stop event or the stream-switch event
376 // is signaled. An error event can also break the main thread loop. 394 // is signaled. An error event can also break the main thread loop.
377 while (playing && !error) { 395 while (playing && !error) {
378 // Wait for a close-down event, stream-switch event or a new render event. 396 // Wait for a close-down event, stream-switch event or a new render event.
379 DWORD wait_result = WaitForMultipleObjects(arraysize(wait_array), 397 DWORD wait_result = WaitForMultipleObjects(arraysize(wait_array),
380 wait_array, 398 wait_array,
381 FALSE, 399 FALSE,
382 INFINITE); 400 INFINITE);
383 401
384 switch (wait_result) { 402 switch (wait_result) {
385 case WAIT_OBJECT_0 + 0: 403 case WAIT_OBJECT_0 + 0:
386 // |stop_render_event_| has been set. 404 // |stop_render_event_| has been set.
387 playing = false; 405 playing = false;
388 break; 406 break;
389 case WAIT_OBJECT_0 + 1: 407 case WAIT_OBJECT_0 + 1:
390 // |audio_samples_render_event_| has been set. 408 // |audio_samples_render_event_| has been set.
391 error = !RenderAudioFromSource(device_frequency); 409 error = !RenderAudioFromSource(device_frequency, thread_audio_client,
410 thread_audio_render_client,
411 thread_audio_clock);
392 break; 412 break;
393 default: 413 default:
394 error = true; 414 error = true;
395 break; 415 break;
396 } 416 }
397 } 417 }
398 418
399 if (playing && error) { 419 if (playing && error && thread_audio_client) {
400 // Stop audio rendering since something has gone wrong in our main thread 420 // Stop audio rendering since something has gone wrong in our main thread
401 // loop. Note that, we are still in a "started" state, hence a Stop() call 421 // loop. Note that, we are still in a "started" state, hence a Stop() call
402 // is required to join the thread properly. 422 // is required to join the thread properly.
403 audio_client_->Stop(); 423 thread_audio_client->Stop();
404 PLOG(ERROR) << "WASAPI rendering failed."; 424 PLOG(ERROR) << "WASAPI rendering failed.";
405 } 425 }
406 426
407 // Disable MMCSS. 427 // Disable MMCSS.
408 if (mm_task && !avrt::AvRevertMmThreadCharacteristics(mm_task)) { 428 if (mm_task && !avrt::AvRevertMmThreadCharacteristics(mm_task)) {
409 PLOG(WARNING) << "Failed to disable MMCSS"; 429 PLOG(WARNING) << "Failed to disable MMCSS";
410 } 430 }
411 } 431 }
412 432
413 bool WASAPIAudioOutputStream::RenderAudioFromSource(UINT64 device_frequency) { 433 bool WASAPIAudioOutputStream::RenderAudioFromSource(
434 UINT64 device_frequency,
435 IAudioClient* thread_audio_client,
436 IAudioRenderClient* thread_audio_render_client,
437 IAudioClock* thread_audio_clock) {
414 TRACE_EVENT0("audio", "RenderAudioFromSource"); 438 TRACE_EVENT0("audio", "RenderAudioFromSource");
415 439
416 HRESULT hr = S_FALSE; 440 HRESULT hr = S_FALSE;
417 UINT32 num_queued_frames = 0; 441 UINT32 num_queued_frames = 0;
418 uint8* audio_data = NULL; 442 uint8* audio_data = NULL;
419 443
420 // Contains how much new data we can write to the buffer without 444 // Contains how much new data we can write to the buffer without
421 // the risk of overwriting previously written data that the audio 445 // the risk of overwriting previously written data that the audio
422 // engine has not yet read from the buffer. 446 // engine has not yet read from the buffer.
423 size_t num_available_frames = 0; 447 size_t num_available_frames = 0;
424 448
425 if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { 449 if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
426 // Get the padding value which represents the amount of rendering 450 // Get the padding value which represents the amount of rendering
427 // data that is queued up to play in the endpoint buffer. 451 // data that is queued up to play in the endpoint buffer.
428 hr = audio_client_->GetCurrentPadding(&num_queued_frames); 452 hr = thread_audio_client->GetCurrentPadding(&num_queued_frames);
429 num_available_frames = 453 num_available_frames =
430 endpoint_buffer_size_frames_ - num_queued_frames; 454 endpoint_buffer_size_frames_ - num_queued_frames;
431 if (FAILED(hr)) { 455 if (FAILED(hr)) {
432 DLOG(ERROR) << "Failed to retrieve amount of available space: " 456 DLOG(ERROR) << "Failed to retrieve amount of available space: "
433 << std::hex << hr; 457 << std::hex << hr;
434 return false; 458 return false;
435 } 459 }
436 } else { 460 } else {
437 // While the stream is running, the system alternately sends one 461 // While the stream is running, the system alternately sends one
438 // buffer or the other to the client. This form of double buffering 462 // buffer or the other to the client. This form of double buffering
(...skipping 21 matching lines...) Expand all
460 // fill up the available area in the endpoint buffer. 484 // fill up the available area in the endpoint buffer.
461 // |num_packets| will always be one for exclusive-mode streams and 485 // |num_packets| will always be one for exclusive-mode streams and
462 // will be one in most cases for shared mode streams as well. 486 // will be one in most cases for shared mode streams as well.
463 // However, we have found that two packets can sometimes be 487 // However, we have found that two packets can sometimes be
464 // required. 488 // required.
465 size_t num_packets = (num_available_frames / packet_size_frames_); 489 size_t num_packets = (num_available_frames / packet_size_frames_);
466 490
467 for (size_t n = 0; n < num_packets; ++n) { 491 for (size_t n = 0; n < num_packets; ++n) {
468 // Grab all available space in the rendering endpoint buffer 492 // Grab all available space in the rendering endpoint buffer
469 // into which the client can write a data packet. 493 // into which the client can write a data packet.
470 hr = audio_render_client_->GetBuffer(packet_size_frames_, 494 hr =
471 &audio_data); 495 thread_audio_render_client->GetBuffer(packet_size_frames_, &audio_data);
472 if (FAILED(hr)) { 496 if (FAILED(hr)) {
473 DLOG(ERROR) << "Failed to use rendering audio buffer: " 497 DLOG(ERROR) << "Failed to use rendering audio buffer: "
474 << std::hex << hr; 498 << std::hex << hr;
475 return false; 499 return false;
476 } 500 }
477 501
478 // Derive the audio delay which corresponds to the delay between 502 // Derive the audio delay which corresponds to the delay between
479 // a render event and the time when the first audio sample in a 503 // a render event and the time when the first audio sample in a
480 // packet is played out through the speaker. This delay value 504 // packet is played out through the speaker. This delay value
481 // can typically be utilized by an acoustic echo-control (AEC) 505 // can typically be utilized by an acoustic echo-control (AEC)
482 // unit at the render side. 506 // unit at the render side.
483 UINT64 position = 0; 507 UINT64 position = 0;
484 uint32 audio_delay_bytes = 0; 508 uint32 audio_delay_bytes = 0;
485 hr = audio_clock_->GetPosition(&position, NULL); 509 hr = thread_audio_clock->GetPosition(&position, NULL);
486 if (SUCCEEDED(hr)) { 510 if (SUCCEEDED(hr)) {
487 // Stream position of the sample that is currently playing 511 // Stream position of the sample that is currently playing
488 // through the speaker. 512 // through the speaker.
489 double pos_sample_playing_frames = format_.Format.nSamplesPerSec * 513 double pos_sample_playing_frames = format_.Format.nSamplesPerSec *
490 (static_cast<double>(position) / device_frequency); 514 (static_cast<double>(position) / device_frequency);
491 515
492 // Stream position of the last sample written to the endpoint 516 // Stream position of the last sample written to the endpoint
493 // buffer. Note that, the packet we are about to receive in 517 // buffer. Note that, the packet we are about to receive in
494 // the upcoming callback is also included. 518 // the upcoming callback is also included.
495 size_t pos_last_sample_written_frames = 519 size_t pos_last_sample_written_frames =
(...skipping 19 matching lines...) Expand all
515 const int bytes_per_sample = format_.Format.wBitsPerSample >> 3; 539 const int bytes_per_sample = format_.Format.wBitsPerSample >> 3;
516 audio_bus_->Scale(volume_); 540 audio_bus_->Scale(volume_);
517 audio_bus_->ToInterleaved( 541 audio_bus_->ToInterleaved(
518 frames_filled, bytes_per_sample, audio_data); 542 frames_filled, bytes_per_sample, audio_data);
519 543
520 544
521 // Release the buffer space acquired in the GetBuffer() call. 545 // Release the buffer space acquired in the GetBuffer() call.
522 // Render silence if we were not able to fill up the buffer totally. 546 // Render silence if we were not able to fill up the buffer totally.
523 DWORD flags = (num_filled_bytes < packet_size_bytes_) ? 547 DWORD flags = (num_filled_bytes < packet_size_bytes_) ?
524 AUDCLNT_BUFFERFLAGS_SILENT : 0; 548 AUDCLNT_BUFFERFLAGS_SILENT : 0;
525 audio_render_client_->ReleaseBuffer(packet_size_frames_, flags); 549 thread_audio_render_client->ReleaseBuffer(packet_size_frames_, flags);
526 550
527 num_written_frames_ += packet_size_frames_; 551 num_written_frames_ += packet_size_frames_;
528 } 552 }
529 553
530 return true; 554 return true;
531 } 555 }
532 556
533 HRESULT WASAPIAudioOutputStream::ExclusiveModeInitialization( 557 HRESULT WASAPIAudioOutputStream::ExclusiveModeInitialization(
534 IAudioClient* client, HANDLE event_handle, uint32* endpoint_buffer_size) { 558 IAudioClient* client, HANDLE event_handle, uint32* endpoint_buffer_size) {
535 DCHECK_EQ(share_mode_, AUDCLNT_SHAREMODE_EXCLUSIVE); 559 DCHECK_EQ(share_mode_, AUDCLNT_SHAREMODE_EXCLUSIVE);
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 render_thread_.reset(); 644 render_thread_.reset();
621 645
622 // Ensure that we don't quit the main thread loop immediately next 646 // Ensure that we don't quit the main thread loop immediately next
623 // time Start() is called. 647 // time Start() is called.
624 ResetEvent(stop_render_event_.Get()); 648 ResetEvent(stop_render_event_.Get());
625 } 649 }
626 650
627 source_ = NULL; 651 source_ = NULL;
628 } 652 }
629 653
654 bool WASAPIAudioOutputStream::MarshalComPointers() {
655 HRESULT hr = CreateStreamOnHGlobal(0, TRUE, &com_stream_);
656 if (FAILED(hr)) {
657 DLOG(ERROR) << "Failed to create stream for marshaling COM pointers.";
658 com_stream_ = NULL;
659 return false;
660 }
661
662 hr = CoMarshalInterface(com_stream_, __uuidof(IAudioClient),
663 audio_client_.get(), MSHCTX_INPROC, NULL,
664 MSHLFLAGS_NORMAL);
665 if (FAILED(hr)) {
666 DLOG(ERROR) << "Marshal failed for IAudioClient: " << std::hex << hr;
667 if (com_stream_) {
668 CoReleaseMarshalData(com_stream_);
669 com_stream_ = NULL;
670 }
671 return false;
672 }
673
674 hr = CoMarshalInterface(com_stream_, __uuidof(IAudioRenderClient),
675 audio_render_client_.get(), MSHCTX_INPROC, NULL,
676 MSHLFLAGS_NORMAL);
677 if (FAILED(hr)) {
678 DLOG(ERROR) << "Marshal failed for IAudioRenderClient: " << std::hex << hr;
679 CoReleaseMarshalData(com_stream_);
680 com_stream_ = NULL;
681 return false;
682 }
683
684 hr =
685 CoMarshalInterface(com_stream_, __uuidof(IAudioClock), audio_clock_.get(),
686 MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
687 if (FAILED(hr)) {
688 DLOG(ERROR) << "Marshal failed for IAudioClock: " << std::hex << hr;
689 CoReleaseMarshalData(com_stream_);
690 com_stream_ = NULL;
691 return false;
692 }
693
694 LARGE_INTEGER pos = {0};
695 hr = com_stream_->Seek(pos, STREAM_SEEK_SET, NULL);
696 if (FAILED(hr)) {
697 DLOG(ERROR) << "Failed to seek IStream for marshaling: " << std::hex << hr;
698 CoReleaseMarshalData(com_stream_);
699 com_stream_ = NULL;
700 return false;
701 }
702
703 return true;
704 }
705
706 bool WASAPIAudioOutputStream::UnmarshalComPointers(
707 IAudioClient** audio_client,
708 IAudioRenderClient** audio_render_client,
709 IAudioClock** audio_clock) {
710 HRESULT hr = CoUnmarshalInterface(com_stream_, __uuidof(IAudioClient),
711 reinterpret_cast<LPVOID*>(audio_client));
712 if (FAILED(hr)) {
713 DLOG(ERROR) << "Unmarshal failed IAudioClient: " << std::hex << hr;
714 CoReleaseMarshalData(com_stream_);
715 com_stream_ = NULL;
716 return false;
717 }
718
719 hr = CoUnmarshalInterface(com_stream_, __uuidof(IAudioRenderClient),
720 reinterpret_cast<LPVOID*>(audio_render_client));
721 if (FAILED(hr)) {
722 DLOG(ERROR) << "Unmarshal failed IAudioRenderClient: " << std::hex << hr;
723 CoReleaseMarshalData(com_stream_);
724 com_stream_ = NULL;
725 return false;
726 }
727
728 hr = CoUnmarshalInterface(com_stream_, __uuidof(IAudioClock),
729 reinterpret_cast<LPVOID*>(audio_clock));
730 if (FAILED(hr))
731 DLOG(ERROR) << "Unmarshal failed IAudioClock: " << std::hex << hr;
732 CoReleaseMarshalData(com_stream_);
733 com_stream_ = NULL;
734 return SUCCEEDED(hr);
735 }
736
630 } // namespace media 737 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698