ml: lay the foundation of SODA in CrOS

1. Add the helper files soda.{h,cc} for the proxy of libsoda.so.
2. We have soda_recognizer_impl.cc and soda_recognizer_impl_dummy.cc.
The former is the real implementation and will be used when "internal"
and "ondevice_speech" are used. Otherwise, the latter will be used and
it will cause crash/errors during tests.

BUG=b:160550533
TEST=SODA works on device (can recognize and send the result to Chrome).
TEST=both `USE=ondevice_speech emerge-eve ml` and ` emerge-eve ml` work

Cq-Depend: 2374425
Change-Id: Ieb453a4ae97807a8a4eecba010a0cdb0521eada9
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2377167
Reviewed-by: Michael Mortensen <mmortensen@google.com>
Reviewed-by: Andrew Moylan <amoylan@chromium.org>
Tested-by: Honglin Yu <honglinyu@chromium.org>
Commit-Queue: Honglin Yu <honglinyu@chromium.org>
diff --git a/ml/machine_learning_service_impl.cc b/ml/machine_learning_service_impl.cc
index 9987a2f..02d76ab 100644
--- a/ml/machine_learning_service_impl.cc
+++ b/ml/machine_learning_service_impl.cc
@@ -22,6 +22,8 @@
 #include "ml/model_impl.h"
 #include "ml/mojom/handwriting_recognizer.mojom.h"
 #include "ml/mojom/model.mojom.h"
+#include "ml/mojom/soda.mojom.h"
+#include "ml/soda_recognizer_impl.h"
 #include "ml/text_classifier_impl.h"
 
 namespace ml {
@@ -38,6 +40,9 @@
 using ::chromeos::machine_learning::mojom::LoadModelResult;
 using ::chromeos::machine_learning::mojom::MachineLearningService;
 using ::chromeos::machine_learning::mojom::Model;
+using ::chromeos::machine_learning::mojom::SodaClient;
+using ::chromeos::machine_learning::mojom::SodaConfigPtr;
+using ::chromeos::machine_learning::mojom::SodaRecognizer;
 using ::chromeos::machine_learning::mojom::TextClassifier;
 
 constexpr char kSystemModelDir[] = "/opt/google/chrome/ml_models/";
@@ -344,6 +349,32 @@
   request_metrics.RecordRequestEvent(LoadModelResult::OK);
 }
 
+void MachineLearningServiceImpl::LoadSpeechRecognizer(
+    SodaConfigPtr config,
+    mojo::PendingRemote<SodaClient> soda_client,
+    mojo::PendingReceiver<SodaRecognizer> soda_recognizer,
+    LoadSpeechRecognizerCallback callback) {
+  RequestMetrics request_metrics("Soda", kMetricsRequestName);
+  request_metrics.StartRecordingPerformanceMetrics();
+
+  // Create the SodaRecognizer.
+  if (!SodaRecognizerImpl::Create(std::move(config), std::move(soda_client),
+                                  std::move(soda_recognizer))) {
+    LOG(ERROR) << "Failed to create SodaRecognizerImpl object.";
+    // TODO(robsc): it may be better that SODA has its specific enum values to
+    // return, similar to handwriting. So before we finalize the impl of SODA
+    // Mojo API, we may revisit this return value.
+    std::move(callback).Run(LoadModelResult::LOAD_MODEL_ERROR);
+    request_metrics.RecordRequestEvent(LoadModelResult::LOAD_MODEL_ERROR);
+    return;
+  }
+
+  std::move(callback).Run(LoadModelResult::OK);
+
+  request_metrics.FinishRecordingPerformanceMetrics();
+  request_metrics.RecordRequestEvent(LoadModelResult::OK);
+}
+
 void MachineLearningServiceImpl::InitIcuIfNeeded() {
   if (icu_data_ == nullptr) {
     // Need to load the data file again.