OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |