Skip to content

Commit

Permalink
Move stream_factory.mojom to media/mojo/mojom/.
Browse files Browse the repository at this point in the history
In order to support offline speech recognition of microphone input,
we plan to add a method to SpeechRecognitionContext that takes a
StreamFactory. However, StreamFactory depends on media::mojom, so
adding StreamFactory to speech_recognition_service.mojom in media/
will create a circular dependency.

This change moves services/audio/public/mojom/stream_factory.mojom
to media/mojo/mojom/stream_factory.mojom to avoid that circular
dependency, and renames StreamFactory to AudioStreamFactory.

This change makes no functional changes.

Proposed addition to speech_recognition_service.mojom (follow-up):
```
// Allows audio to be captured from within the SpeechRecognitionService
// process, with results passed back to the
// SpeechRecognitionRecognizerClient.
BindAudioSourceRecognizer(
               pending_receiver<AudioSourceFetcher> fetcher_receiver,
               pending_remote<SpeechRecognitionRecognizerClient> client,
               pending_remote<media.mojom.AudioStreamFactory> factory)
               => (bool success);
```

See design at go/cros-dictation-with-soda (audio input header).

Bug: 1173135
Change-Id: Ifa286d628b8d4398b41f0b2daed704989ef5fe84
AX-Relnote: N/A
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2718486
Reviewed-by: Alex Gough <ajgo@chromium.org>
Reviewed-by: Jeroen Dhollander <jeroendh@chromium.org>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: Evan Liu <evliu@google.com>
Reviewed-by: Xiyuan Xia <xiyuan@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Commit-Queue: Katie Dektar <katie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#859106}
  • Loading branch information
Katie Dektar authored and Chromium LUCI CQ committed Mar 2, 2021
1 parent 5be8a24 commit eb981e7
Show file tree
Hide file tree
Showing 83 changed files with 227 additions and 203 deletions.
2 changes: 1 addition & 1 deletion ash/capture_mode/capture_mode_controller.cc
Expand Up @@ -726,7 +726,7 @@ void CaptureModeController::LaunchRecordingServiceAndStartRecording(
// We bind the audio stream factory only if audio recording is enabled. This
// is ok since the |audio_stream_factory| parameter in the recording service
// APIs is optional, and can be not bound.
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory;
mojo::PendingRemote<media::mojom::AudioStreamFactory> audio_stream_factory;
if (enable_audio_recording_) {
delegate_->BindAudioStreamFactory(
audio_stream_factory.InitWithNewPipeAndPassReceiver());
Expand Down
11 changes: 7 additions & 4 deletions ash/capture_mode/test_capture_mode_delegate.cc
Expand Up @@ -36,7 +36,8 @@ class FakeRecordingService : public recording::mojom::RecordingService {
void RecordFullscreen(
mojo::PendingRemote<recording::mojom::RecordingServiceClient> client,
mojo::PendingRemote<viz::mojom::FrameSinkVideoCapturer> video_capturer,
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory,
mojo::PendingRemote<media::mojom::AudioStreamFactory>
audio_stream_factory,
const viz::FrameSinkId& frame_sink_id,
const gfx::Size& frame_sink_size) override {
remote_client_.Bind(std::move(client));
Expand All @@ -48,7 +49,8 @@ class FakeRecordingService : public recording::mojom::RecordingService {
void RecordWindow(
mojo::PendingRemote<recording::mojom::RecordingServiceClient> client,
mojo::PendingRemote<viz::mojom::FrameSinkVideoCapturer> video_capturer,
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory,
mojo::PendingRemote<media::mojom::AudioStreamFactory>
audio_stream_factory,
const viz::FrameSinkId& frame_sink_id,
const gfx::Size& frame_sink_size,
const viz::SubtreeCaptureId& subtree_capture_id,
Expand All @@ -62,7 +64,8 @@ class FakeRecordingService : public recording::mojom::RecordingService {
void RecordRegion(
mojo::PendingRemote<recording::mojom::RecordingServiceClient> client,
mojo::PendingRemote<viz::mojom::FrameSinkVideoCapturer> video_capturer,
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory,
mojo::PendingRemote<media::mojom::AudioStreamFactory>
audio_stream_factory,
const viz::FrameSinkId& frame_sink_id,
const gfx::Size& frame_sink_size,
const gfx::Rect& crop_region) override {
Expand Down Expand Up @@ -170,7 +173,7 @@ TestCaptureModeDelegate::LaunchRecordingService() {
}

void TestCaptureModeDelegate::BindAudioStreamFactory(
mojo::PendingReceiver<audio::mojom::StreamFactory> receiver) {}
mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver) {}

void TestCaptureModeDelegate::OnSessionStateChanged(bool started) {}

Expand Down
3 changes: 2 additions & 1 deletion ash/capture_mode/test_capture_mode_delegate.h
Expand Up @@ -51,7 +51,8 @@ class TestCaptureModeDelegate : public CaptureModeDelegate {
mojo::Remote<recording::mojom::RecordingService> LaunchRecordingService()
override;
void BindAudioStreamFactory(
mojo::PendingReceiver<audio::mojom::StreamFactory> receiver) override;
mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver)
override;
void OnSessionStateChanged(bool started) override;

private:
Expand Down
16 changes: 8 additions & 8 deletions ash/public/cpp/capture_mode_delegate.h
Expand Up @@ -10,12 +10,6 @@
#include "base/callback.h"
#include "mojo/public/cpp/bindings/remote.h"

namespace audio {
namespace mojom {
class StreamFactory;
} // namespace mojom
} // namespace audio

namespace aura {
class Window;
} // namespace aura
Expand All @@ -28,6 +22,12 @@ namespace gfx {
class Rect;
} // namespace gfx

namespace media {
namespace mojom {
class AudioStreamFactory;
} // namespace mojom
} // namespace media

namespace ash {

// Defines the interface for the delegate of CaptureModeController, that can be
Expand Down Expand Up @@ -82,9 +82,9 @@ class ASH_PUBLIC_EXPORT CaptureModeDelegate {
virtual mojo::Remote<recording::mojom::RecordingService>
LaunchRecordingService() = 0;

// Binds the given audio StreamFactory |receiver| to the audio service.
// Binds the given AudioStreamFactory |receiver| to the audio service.
virtual void BindAudioStreamFactory(
mojo::PendingReceiver<audio::mojom::StreamFactory> receiver) = 0;
mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver) = 0;

// Called when a capture mode session starts or stops.
virtual void OnSessionStateChanged(bool started) = 0;
Expand Down
1 change: 0 additions & 1 deletion ash/services/recording/public/mojom/BUILD.gn
Expand Up @@ -9,7 +9,6 @@ mojom("mojom") {

deps = [
"//media/mojo/mojom",
"//services/audio/public/mojom",
"//services/viz/privileged/mojom/compositing",
]
}
8 changes: 4 additions & 4 deletions ash/services/recording/public/mojom/recording_service.mojom
Expand Up @@ -4,8 +4,8 @@

module recording.mojom;

import "media/mojo/mojom/audio_stream_factory.mojom";
import "mojo/public/mojom/base/big_string.mojom";
import "services/audio/public/mojom/stream_factory.mojom";
import "services/viz/privileged/mojom/compositing/frame_sink_video_capture.mojom";
import "services/viz/public/mojom/compositing/frame_sink_id.mojom";
import "services/viz/public/mojom/compositing/subtree_capture_id.mojom";
Expand Down Expand Up @@ -55,7 +55,7 @@ interface RecordingService {
RecordFullscreen(
pending_remote<RecordingServiceClient> client,
pending_remote<viz.mojom.FrameSinkVideoCapturer> video_capturer,
pending_remote<audio.mojom.StreamFactory>? audio_stream_factory,
pending_remote<media.mojom.AudioStreamFactory>? audio_stream_factory,
viz.mojom.FrameSinkId frame_sink_id,
gfx.mojom.Size frame_sink_size);

Expand All @@ -81,7 +81,7 @@ interface RecordingService {
RecordWindow(
pending_remote<RecordingServiceClient> client,
pending_remote<viz.mojom.FrameSinkVideoCapturer> video_capturer,
pending_remote<audio.mojom.StreamFactory>? audio_stream_factory,
pending_remote<media.mojom.AudioStreamFactory>? audio_stream_factory,
viz.mojom.FrameSinkId frame_sink_id,
gfx.mojom.Size frame_sink_size,
viz.mojom.SubtreeCaptureId subtree_capture_id,
Expand All @@ -100,7 +100,7 @@ interface RecordingService {
RecordRegion(
pending_remote<RecordingServiceClient> client,
pending_remote<viz.mojom.FrameSinkVideoCapturer> video_capturer,
pending_remote<audio.mojom.StreamFactory>? audio_stream_factory,
pending_remote<media.mojom.AudioStreamFactory>? audio_stream_factory,
viz.mojom.FrameSinkId frame_sink_id,
gfx.mojom.Size frame_sink_size,
gfx.mojom.Rect crop_region);
Expand Down
8 changes: 4 additions & 4 deletions ash/services/recording/recording_service.cc
Expand Up @@ -94,7 +94,7 @@ RecordingService::~RecordingService() = default;
void RecordingService::RecordFullscreen(
mojo::PendingRemote<mojom::RecordingServiceClient> client,
mojo::PendingRemote<viz::mojom::FrameSinkVideoCapturer> video_capturer,
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory,
mojo::PendingRemote<media::mojom::AudioStreamFactory> audio_stream_factory,
const viz::FrameSinkId& frame_sink_id,
const gfx::Size& frame_sink_size) {
DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
Expand All @@ -108,7 +108,7 @@ void RecordingService::RecordFullscreen(
void RecordingService::RecordWindow(
mojo::PendingRemote<mojom::RecordingServiceClient> client,
mojo::PendingRemote<viz::mojom::FrameSinkVideoCapturer> video_capturer,
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory,
mojo::PendingRemote<media::mojom::AudioStreamFactory> audio_stream_factory,
const viz::FrameSinkId& frame_sink_id,
const gfx::Size& frame_sink_size,
const viz::SubtreeCaptureId& subtree_capture_id,
Expand All @@ -125,7 +125,7 @@ void RecordingService::RecordWindow(
void RecordingService::RecordRegion(
mojo::PendingRemote<mojom::RecordingServiceClient> client,
mojo::PendingRemote<viz::mojom::FrameSinkVideoCapturer> video_capturer,
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory,
mojo::PendingRemote<media::mojom::AudioStreamFactory> audio_stream_factory,
const viz::FrameSinkId& frame_sink_id,
const gfx::Size& frame_sink_size,
const gfx::Rect& crop_region) {
Expand Down Expand Up @@ -305,7 +305,7 @@ void RecordingService::OnCaptureMuted(bool is_muted) {}
void RecordingService::StartNewRecording(
mojo::PendingRemote<mojom::RecordingServiceClient> client,
mojo::PendingRemote<viz::mojom::FrameSinkVideoCapturer> video_capturer,
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory,
mojo::PendingRemote<media::mojom::AudioStreamFactory> audio_stream_factory,
std::unique_ptr<VideoCaptureParams> capture_params) {
DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);

Expand Down
12 changes: 8 additions & 4 deletions ash/services/recording/recording_service.h
Expand Up @@ -45,21 +45,24 @@ class RecordingService : public mojom::RecordingService,
void RecordFullscreen(
mojo::PendingRemote<mojom::RecordingServiceClient> client,
mojo::PendingRemote<viz::mojom::FrameSinkVideoCapturer> video_capturer,
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory,
mojo::PendingRemote<media::mojom::AudioStreamFactory>
audio_stream_factory,
const viz::FrameSinkId& frame_sink_id,
const gfx::Size& frame_sink_size) override;
void RecordWindow(
mojo::PendingRemote<mojom::RecordingServiceClient> client,
mojo::PendingRemote<viz::mojom::FrameSinkVideoCapturer> video_capturer,
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory,
mojo::PendingRemote<media::mojom::AudioStreamFactory>
audio_stream_factory,
const viz::FrameSinkId& frame_sink_id,
const gfx::Size& frame_sink_size,
const viz::SubtreeCaptureId& subtree_capture_id,
const gfx::Size& window_size) override;
void RecordRegion(
mojo::PendingRemote<mojom::RecordingServiceClient> client,
mojo::PendingRemote<viz::mojom::FrameSinkVideoCapturer> video_capturer,
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory,
mojo::PendingRemote<media::mojom::AudioStreamFactory>
audio_stream_factory,
const viz::FrameSinkId& frame_sink_id,
const gfx::Size& frame_sink_size,
const gfx::Rect& crop_region) override;
Expand Down Expand Up @@ -93,7 +96,8 @@ class RecordingService : public mojom::RecordingService,
void StartNewRecording(
mojo::PendingRemote<mojom::RecordingServiceClient> client,
mojo::PendingRemote<viz::mojom::FrameSinkVideoCapturer> video_capturer,
mojo::PendingRemote<audio::mojom::StreamFactory> audio_stream_factory,
mojo::PendingRemote<media::mojom::AudioStreamFactory>
audio_stream_factory,
std::unique_ptr<VideoCaptureParams> capture_params);

// Called on the main thread during an on-going recording to reconfigure an
Expand Down
6 changes: 3 additions & 3 deletions chrome/browser/media/cast_mirroring_service_host.h
Expand Up @@ -19,12 +19,12 @@
#include "content/public/browser/media_stream_request.h"
#include "content/public/browser/web_contents_observer.h"
#include "extensions/buildflags/buildflags.h"
#include "media/mojo/mojom/audio_stream_factory.mojom.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/audio/public/mojom/stream_factory.mojom.h"
#include "ui/gfx/geometry/size.h"

namespace base {
Expand Down Expand Up @@ -153,12 +153,12 @@ class CastMirroringServiceHost final : public mojom::MirroringServiceHost,

// Used to create WebContents loopback capture streams, or system-wide desktop
// capture streams, from the Audio Service.
mojo::Remote<audio::mojom::StreamFactory> audio_stream_factory_;
mojo::Remote<media::mojom::AudioStreamFactory> audio_stream_factory_;

// Used to mute local audio from the WebContents being mirrored (in the tab
// mirrorng case). See the comments in the implementation of
// CreateAudioStream() for further explanation.
mojo::AssociatedRemote<audio::mojom::LocalMuter> web_contents_audio_muter_;
mojo::AssociatedRemote<media::mojom::LocalMuter> web_contents_audio_muter_;

// The lifetime of the capture indicator icon on the tabstrip is tied to that
// of |media_stream_ui_|.
Expand Down
Expand Up @@ -168,7 +168,7 @@ void TtsEngineExtensionObserverChromeOS::BindTtsStreamFactory(
// Always create a new audio stream for the tts stream. It is assumed once the
// tts stream is reset by the service, the audio stream is appropriately
// cleaned up by the audio service.
mojo::PendingRemote<audio::mojom::StreamFactory> factory_remote;
mojo::PendingRemote<media::mojom::AudioStreamFactory> factory_remote;
auto factory_receiver = factory_remote.InitWithNewPipeAndPassReceiver();
content::GetAudioService().BindStreamFactory(std::move(factory_receiver));
tts_service_->BindTtsStreamFactory(std::move(receiver),
Expand Down
2 changes: 1 addition & 1 deletion chrome/browser/ui/ash/assistant/assistant_client_impl.cc
Expand Up @@ -130,7 +130,7 @@ void AssistantClientImpl::RequestWakeLockProvider(
}

void AssistantClientImpl::RequestAudioStreamFactory(
mojo::PendingReceiver<audio::mojom::StreamFactory> receiver) {
mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver) {
content::GetAudioService().BindStreamFactory(std::move(receiver));
}

Expand Down
3 changes: 2 additions & 1 deletion chrome/browser/ui/ash/assistant/assistant_client_impl.h
Expand Up @@ -63,7 +63,8 @@ class AssistantClientImpl : public ash::AssistantClient,
void RequestWakeLockProvider(
mojo::PendingReceiver<device::mojom::WakeLockProvider> receiver) override;
void RequestAudioStreamFactory(
mojo::PendingReceiver<audio::mojom::StreamFactory> receiver) override;
mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver)
override;
void RequestAudioDecoderFactory(
mojo::PendingReceiver<
chromeos::assistant::mojom::AssistantAudioDecoderFactory> receiver)
Expand Down
2 changes: 1 addition & 1 deletion chrome/browser/ui/ash/chrome_capture_mode_delegate.cc
Expand Up @@ -161,7 +161,7 @@ ChromeCaptureModeDelegate::LaunchRecordingService() {
}

void ChromeCaptureModeDelegate::BindAudioStreamFactory(
mojo::PendingReceiver<audio::mojom::StreamFactory> receiver) {
mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver) {
content::GetAudioService().BindStreamFactory(std::move(receiver));
}

Expand Down
3 changes: 2 additions & 1 deletion chrome/browser/ui/ash/chrome_capture_mode_delegate.h
Expand Up @@ -48,7 +48,8 @@ class ChromeCaptureModeDelegate : public ash::CaptureModeDelegate {
mojo::Remote<recording::mojom::RecordingService> LaunchRecordingService()
override;
void BindAudioStreamFactory(
mojo::PendingReceiver<audio::mojom::StreamFactory> receiver) override;
mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver)
override;
void OnSessionStateChanged(bool started) override;

private:
Expand Down
1 change: 1 addition & 0 deletions chromeos/services/assistant/BUILD.gn
Expand Up @@ -57,6 +57,7 @@ component("lib") {
"//components/prefs",
"//components/signin/public/identity_manager",
"//components/user_manager",
"//media/mojo/mojom",
"//services/media_session/public/cpp",
"//ui/accessibility:ax_assistant",
]
Expand Down
1 change: 1 addition & 0 deletions chromeos/services/assistant/DEPS
Expand Up @@ -7,6 +7,7 @@ include_rules = [
"+google_apis/gaia",
"+libassistant",
"+media/base",
"+media/mojo/mojom",
"+mojo/public",
"+services/audio/public",
"+services/device/public",
Expand Down
Expand Up @@ -17,7 +17,7 @@ void PlatformDelegateImpl::Bind(
}

void PlatformDelegateImpl::BindAudioStreamFactory(
mojo::PendingReceiver<audio::mojom::StreamFactory> receiver) {
mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver) {
AssistantClient::Get()->RequestAudioStreamFactory(std::move(receiver));
}

Expand Down
Expand Up @@ -24,7 +24,8 @@ class PlatformDelegateImpl

// chromeos::libassistant::mojom::PlatformDelegate implementation:
void BindAudioStreamFactory(
mojo::PendingReceiver<audio::mojom::StreamFactory> receiver) override;
mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver)
override;
void BindAudioDecoderFactory(
mojo::PendingReceiver<
chromeos::assistant::mojom::AssistantAudioDecoderFactory> receiver)
Expand Down
6 changes: 3 additions & 3 deletions chromeos/services/assistant/public/cpp/assistant_client.h
Expand Up @@ -11,8 +11,8 @@
#include "chromeos/services/assistant/public/mojom/assistant_audio_decoder.mojom.h"
#include "chromeos/services/libassistant/public/cpp/assistant_notification.h"
#include "chromeos/services/network_config/public/mojom/cros_network_config.mojom.h"
#include "media/mojo/mojom/audio_stream_factory.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "services/audio/public/mojom/stream_factory.mojom.h"
#include "services/device/public/mojom/battery_monitor.mojom.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h"
#include "services/media_session/public/mojom/audio_focus.mojom.h"
Expand Down Expand Up @@ -48,9 +48,9 @@ class COMPONENT_EXPORT(ASSISTANT_SERVICE_PUBLIC) AssistantClient {
virtual void RequestWakeLockProvider(
mojo::PendingReceiver<device::mojom::WakeLockProvider> receiver) = 0;

// Requests an Audio Service StreamFactory from the browser.
// Requests an Audio Service AudioStreamFactory from the browser.
virtual void RequestAudioStreamFactory(
mojo::PendingReceiver<audio::mojom::StreamFactory> receiver) = 0;
mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver) = 0;

// Requests an audio decoder interface from the Assistant Audio Decoder
// service, via the browser.
Expand Down
Expand Up @@ -11,7 +11,7 @@ FakePlatformDelegate::FakePlatformDelegate() = default;
FakePlatformDelegate::~FakePlatformDelegate() = default;

void FakePlatformDelegate::BindAudioStreamFactory(
mojo::PendingReceiver<::audio::mojom::StreamFactory> receiver) {
mojo::PendingReceiver<::media::mojom::AudioStreamFactory> receiver) {
stream_factory_receiver_ = std::move(receiver);
}

Expand Down
Expand Up @@ -23,7 +23,8 @@ class COMPONENT_EXPORT(ASSISTANT_SERVICE_MIGRATION_TEST_SUPPORT)

// mojom::PlatformDelegate implementation:
void BindAudioStreamFactory(
mojo::PendingReceiver<::audio::mojom::StreamFactory> receiver) override;
mojo::PendingReceiver<::media::mojom::AudioStreamFactory> receiver)
override;
void BindAudioDecoderFactory(
mojo::PendingReceiver<
chromeos::assistant::mojom::AssistantAudioDecoderFactory> receiver)
Expand All @@ -41,7 +42,7 @@ class COMPONENT_EXPORT(ASSISTANT_SERVICE_MIGRATION_TEST_SUPPORT)
override {}

// Return the pending receiver passed to the last BindAudioStreamFactory call.
mojo::PendingReceiver<::audio::mojom::StreamFactory>
mojo::PendingReceiver<::media::mojom::AudioStreamFactory>
stream_factory_receiver() {
return std::move(stream_factory_receiver_);
}
Expand All @@ -53,7 +54,8 @@ class COMPONENT_EXPORT(ASSISTANT_SERVICE_MIGRATION_TEST_SUPPORT)
}

private:
mojo::PendingReceiver<::audio::mojom::StreamFactory> stream_factory_receiver_;
mojo::PendingReceiver<::media::mojom::AudioStreamFactory>
stream_factory_receiver_;
mojo::PendingReceiver<::device::mojom::BatteryMonitor>
battery_monitor_receiver_;
};
Expand Down
Expand Up @@ -40,7 +40,8 @@ class ScopedAssistantClient : AssistantClient {
mojo::PendingReceiver<device::mojom::WakeLockProvider> receiver)
override {}
void RequestAudioStreamFactory(
mojo::PendingReceiver<audio::mojom::StreamFactory> receiver) override {}
mojo::PendingReceiver<media::mojom::AudioStreamFactory> receiver)
override {}
void RequestAudioDecoderFactory(
mojo::PendingReceiver<mojom::AssistantAudioDecoderFactory> receiver)
override {}
Expand Down

0 comments on commit eb981e7

Please sign in to comment.