mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	- Mac: Xcode 12.2 and the MacOS 11.0 SDK are now required for building. - MacOS 10.10 (Yosemite) is no longer supported (see https://crbug.com/1126056). - Flash is no longer supported (see https://www.chromium.org/flash-roadmap).
		
			
				
	
	
		
			126 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright (c) 2019 The Chromium Embedded Framework Authors.
 | 
						|
// Portions copyright (c) 2011 The Chromium Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style license that can be
 | 
						|
// found in the LICENSE file.
 | 
						|
 | 
						|
#include "libcef/browser/audio_capturer.h"
 | 
						|
 | 
						|
#include "libcef/browser/alloy/alloy_browser_host_impl.h"
 | 
						|
#include "libcef/browser/audio_loopback_stream_creator.h"
 | 
						|
 | 
						|
#include "components/mirroring/service/captured_audio_input.h"
 | 
						|
#include "media/audio/audio_input_device.h"
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
media::ChannelLayout TranslateChannelLayout(
 | 
						|
    cef_channel_layout_t channel_layout) {
 | 
						|
  // Verify that our enum matches Chromium's values. The enum values match
 | 
						|
  // between those enums and existing values don't ever change, so it's enough
 | 
						|
  // to check that there are no new ones added.
 | 
						|
  static_assert(
 | 
						|
      static_cast<int>(CEF_CHANNEL_LAYOUT_MAX) ==
 | 
						|
          static_cast<int>(media::CHANNEL_LAYOUT_MAX),
 | 
						|
      "cef_channel_layout_t must match the ChannelLayout enum in Chromium");
 | 
						|
  return static_cast<media::ChannelLayout>(channel_layout);
 | 
						|
}
 | 
						|
 | 
						|
void StreamCreatorHelper(
 | 
						|
    content::WebContents* source_web_contents,
 | 
						|
    CefAudioLoopbackStreamCreator* audio_stream_creator,
 | 
						|
    mojo::PendingRemote<mirroring::mojom::AudioStreamCreatorClient> client,
 | 
						|
    const media::AudioParameters& params,
 | 
						|
    uint32_t total_segments) {
 | 
						|
  audio_stream_creator->CreateLoopbackStream(
 | 
						|
      source_web_contents, params, total_segments,
 | 
						|
      base::BindRepeating(
 | 
						|
          [](mojo::PendingRemote<mirroring::mojom::AudioStreamCreatorClient>
 | 
						|
                 client,
 | 
						|
             mojo::PendingRemote<media::mojom::AudioInputStream> stream,
 | 
						|
             mojo::PendingReceiver<media::mojom::AudioInputStreamClient>
 | 
						|
                 client_receiver,
 | 
						|
             media::mojom::ReadOnlyAudioDataPipePtr data_pipe) {
 | 
						|
            mojo::Remote<mirroring::mojom::AudioStreamCreatorClient>
 | 
						|
                audio_client(std::move(client));
 | 
						|
            audio_client->StreamCreated(std::move(stream),
 | 
						|
                                        std::move(client_receiver),
 | 
						|
                                        std::move(data_pipe));
 | 
						|
          },
 | 
						|
          base::Passed(&client)));
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
CefAudioCapturer::CefAudioCapturer(const CefAudioParameters& params,
 | 
						|
                                   CefRefPtr<AlloyBrowserHostImpl> browser,
 | 
						|
                                   CefRefPtr<CefAudioHandler> audio_handler)
 | 
						|
    : params_(params),
 | 
						|
      browser_(browser),
 | 
						|
      audio_handler_(audio_handler),
 | 
						|
      audio_stream_creator_(std::make_unique<CefAudioLoopbackStreamCreator>()) {
 | 
						|
  media::AudioParameters audio_params(
 | 
						|
      media::AudioParameters::AUDIO_PCM_LINEAR,
 | 
						|
      TranslateChannelLayout(params.channel_layout), params.sample_rate,
 | 
						|
      params.frames_per_buffer);
 | 
						|
 | 
						|
  if (!audio_params.IsValid()) {
 | 
						|
    LOG(ERROR) << "Invalid audio parameters";
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  DCHECK(browser_);
 | 
						|
  DCHECK(audio_handler_);
 | 
						|
  DCHECK(browser_->web_contents());
 | 
						|
 | 
						|
  channels_ = audio_params.channels();
 | 
						|
  audio_input_device_ = new media::AudioInputDevice(
 | 
						|
      std::make_unique<mirroring::CapturedAudioInput>(base::BindRepeating(
 | 
						|
          &StreamCreatorHelper, base::Unretained(browser_->web_contents()),
 | 
						|
          base::Unretained(audio_stream_creator_.get()))),
 | 
						|
      media::AudioInputDevice::kLoopback,
 | 
						|
      media::AudioInputDevice::DeadStreamDetection::kEnabled);
 | 
						|
 | 
						|
  audio_input_device_->Initialize(audio_params, this);
 | 
						|
  audio_input_device_->Start();
 | 
						|
}
 | 
						|
 | 
						|
CefAudioCapturer::~CefAudioCapturer() {
 | 
						|
  StopStream();
 | 
						|
}
 | 
						|
 | 
						|
void CefAudioCapturer::OnCaptureStarted() {
 | 
						|
  audio_handler_->OnAudioStreamStarted(browser_, params_, channels_);
 | 
						|
  DCHECK(!capturing_);
 | 
						|
  capturing_ = true;
 | 
						|
}
 | 
						|
 | 
						|
void CefAudioCapturer::Capture(const media::AudioBus* source,
 | 
						|
                               base::TimeTicks audio_capture_time,
 | 
						|
                               double /*volume*/,
 | 
						|
                               bool /*key_pressed*/) {
 | 
						|
  const int channels = source->channels();
 | 
						|
  std::array<const float*, media::CHANNELS_MAX> data;
 | 
						|
  DCHECK(channels == channels_);
 | 
						|
  DCHECK(channels <= static_cast<int>(data.size()));
 | 
						|
  for (int c = 0; c < channels; ++c) {
 | 
						|
    data[c] = source->channel(c);
 | 
						|
  }
 | 
						|
  base::TimeDelta pts = audio_capture_time - base::TimeTicks::UnixEpoch();
 | 
						|
  audio_handler_->OnAudioStreamPacket(browser_, data.data(), source->frames(),
 | 
						|
                                      pts.InMilliseconds());
 | 
						|
}
 | 
						|
 | 
						|
void CefAudioCapturer::OnCaptureError(const std::string& message) {
 | 
						|
  audio_handler_->OnAudioStreamError(browser_, message);
 | 
						|
  StopStream();
 | 
						|
}
 | 
						|
 | 
						|
void CefAudioCapturer::StopStream() {
 | 
						|
  if (audio_input_device_)
 | 
						|
    audio_input_device_->Stop();
 | 
						|
  if (capturing_)
 | 
						|
    audio_handler_->OnAudioStreamStopped(browser_);
 | 
						|
 | 
						|
  audio_input_device_ = nullptr;
 | 
						|
  capturing_ = false;
 | 
						|
} |