Bug 1201590 - Rust Test MIDI Service draft
authorKyle Machulis <kyle@nonpolynomial.com>
Thu, 28 Jul 2016 14:43:07 -0700
changeset 430384 a8958f5b0e21cb0ce95f5a449b8f477de72af4f4
parent 430383 6e59b98f4f8fc0503d82a0668dee2b162cea7828
child 535193 25af7e160b2058c32ab1071d47f6142b52255d83
push id33813
push userbmo:kyle@nonpolynomial.com
push dateThu, 27 Oct 2016 17:50:59 +0000
bugs1201590
milestone52.0a1
Bug 1201590 - Rust Test MIDI Service MozReview-Commit-ID: FHg5H4luk0Q
dom/midi/MIDIPlatformRunnables.cpp
dom/midi/MIDIPlatformRunnables.h
dom/midi/MIDIPlatformService.cpp
dom/midi/MIDIPort.cpp
dom/midi/TestMIDIPlatform.h
dom/midi/TestMIDIPlatformService.cpp
media/webmidi-rs/.gitignore
media/webmidi-rs/Cargo.toml
media/webmidi-rs/src/lib.rs
media/webmidi-rs/src/platform/linux/mod.rs
media/webmidi-rs/src/platform/macos/mod.rs
media/webmidi-rs/src/platform/mod.rs
media/webmidi-rs/src/platform/test/mod.rs
media/webmidi-rs/src/platform/windows/mod.rs
old-configure.in
toolkit/library/gtest/rust/Cargo.lock
toolkit/library/rust/Cargo.lock
toolkit/library/rust/shared/Cargo.toml
toolkit/library/rust/shared/lib.rs
--- a/dom/midi/MIDIPlatformRunnables.cpp
+++ b/dom/midi/MIDIPlatformRunnables.cpp
@@ -4,16 +4,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/MIDIPlatformRunnables.h"
 #include "mozilla/dom/MIDIPlatformService.h"
 #include "mozilla/dom/MIDIPortParent.h"
 #include "mozilla/ipc/BackgroundParent.h"
 
+StaticRefPtr<nsIThread> gBGThread;
+
 namespace mozilla {
 namespace dom {
 
 NS_IMETHODIMP
 MIDIBackgroundRunnable::Run()
 {
   AssertIsOnBackgroundThread();
   if (!MIDIPlatformService::IsRunning()) {
@@ -53,10 +55,38 @@ SendPortListRunnable::RunInternal()
   // Unlike other runnables, SendPortListRunnable should just exit quietly if
   // the service has died.
   if (!MIDIPlatformService::IsRunning()) {
     return;
   }
   MIDIPlatformService::Get()->SendPortList();
 }
 
+void
+set_midi_background_thread(nsIThread* aBGThread) {
+  gBGThread = aBGThread;
+}
+
 } // namespace dom
 } // namespace mozilla
+
+extern "C" {
+void
+midi_add_port_extern(const nsAString* aId,
+                     const nsAString* aName,
+                     const nsAString* aManufacturer,
+                     const nsAString* aVersion,
+                     uint32_t aType) {
+  MIDIPortInfo i(nsString(*aId),
+                 nsString(*aName),
+                 nsString(*aManufacturer),
+                 nsString(*aVersion),
+                 aType);
+  nsCOMPtr<nsIRunnable> r(new AddPortRunnable(i));
+  gBGThread->Dispatch(r, NS_DISPATCH_NORMAL);
+}
+
+void
+midi_send_port_list_extern() {
+  nsCOMPtr<nsIRunnable> r(new SendPortListRunnable());
+  gBGThread->Dispatch(r, NS_DISPATCH_NORMAL);
+}
+}
--- a/dom/midi/MIDIPlatformRunnables.h
+++ b/dom/midi/MIDIPlatformRunnables.h
@@ -115,12 +115,24 @@ public:
   ~SetStatusRunnable() {}
   virtual void RunInternal() override;
 private:
   nsString mPortId;
   MIDIPortDeviceState mState;
   MIDIPortConnectionState mConnection;
 };
 
+void set_midi_background_thread();
+
 } // namespace dom
 } // namespace mozilla
 
+extern "C" {
+  void
+  midi_add_port_extern(const nsAString* aId,
+                                  const nsAString* aName,
+                                  const nsAString* aManufacturer,
+                                  const nsAString* aVersion,
+                                  uint32_t aType);
+  void midi_send_port_list_extern();
+
+}
 #endif // mozilla_dom_MIDIPlatformRunnables_h
--- a/dom/midi/MIDIPlatformService.cpp
+++ b/dom/midi/MIDIPlatformService.cpp
@@ -2,21 +2,22 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "MIDIPlatformService.h"
 #include "TestMIDIPlatformService.h"
 #include "TestMIDIPlatform.h"
-#include "mozilla/unused.h"
+#include "mozilla/Unused.h"
 #include "mozilla/dom/PMIDIManagerParent.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/dom/MIDIPortParent.h"
 
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
 
 MIDIPlatformService::MIDIPlatformService() :
   mBackgroundThread(NS_GetCurrentThread()),
   mHasSentPortList(false),
   mMessageQueueMutex("MIDIPlatformServce::mMessageQueueMutex")
@@ -202,16 +203,18 @@ MIDIPlatformService::Get()
   if (!IsRunning()) {
     ErrorResult rv;
     // Uncomment once we have an actual platform library to test.
     //
     // bool useTestService = false;
     // rv = Preferences::GetRootBranch()->GetBoolPref("midi.testing", &useTestService);
     gMIDIPlatformService = new TestMIDIPlatformService();
     gMIDIPlatformService->Init();
+    start_midi_service();
+    set_midi_background_thread(NS_GetCurrentThread());
   }
   return gMIDIPlatformService;
 }
 
 void
 MIDIPlatformService::MaybeStop()
 {
   AssertIsOnBackgroundThread();
@@ -220,16 +223,17 @@ MIDIPlatformService::MaybeStop()
     return;
   }
   // If we have any ports or managers left, we should still be alive.
   if (!mPorts.IsEmpty() ||
       !mManagers.IsEmpty()) {
     return;
   }
   Stop();
+  stop_midi_service();
   gMIDIPlatformService = nullptr;
 }
 
 void
 MIDIPlatformService::AddManager(MIDIManagerParent* p)
 {
   AssertIsOnBackgroundThread();
   mManagers.AppendElement(p);
--- a/dom/midi/MIDIPort.cpp
+++ b/dom/midi/MIDIPort.cpp
@@ -7,17 +7,17 @@
 #include "mozilla/dom/MIDIPort.h"
 #include "mozilla/dom/MIDIPortChild.h"
 #include "mozilla/dom/MIDIAccess.h"
 #include "mozilla/dom/MIDITypes.h"
 #include "mozilla/ipc/PBackgroundChild.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/MIDITypes.h"
-#include "mozilla/unused.h"
+#include "mozilla/Unused.h"
 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, MOZ_COUNT_DTOR
 
 using namespace mozilla::ipc;
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(MIDIPort)
new file mode 100644
--- /dev/null
+++ b/dom/midi/TestMIDIPlatform.h
@@ -0,0 +1,18 @@
+
+#ifndef cheddar_generated_testmidiplatform_h
+#define cheddar_generated_testmidiplatform_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void midi_new();
+void call_outside_func();
+void start_midi_service();
+void stop_midi_service();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- a/dom/midi/TestMIDIPlatformService.cpp
+++ b/dom/midi/TestMIDIPlatformService.cpp
@@ -4,17 +4,17 @@
 
 #include "TestMIDIPlatformService.h"
 #include "mozilla/dom/MIDIPort.h"
 #include "mozilla/dom/MIDITypes.h"
 #include "mozilla/dom/MIDIPortInterface.h"
 #include "mozilla/dom/MIDIPortParent.h"
 #include "mozilla/dom/MIDIPlatformRunnables.h"
 #include "mozilla/ipc/BackgroundParent.h"
-#include "mozilla/unused.h"
+#include "mozilla/Unused.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::ipc;
 
 /**
  * Runnable used for making sure ProcessMessages only happens on the IO thread.
  *
new file mode 100644
--- /dev/null
+++ b/media/webmidi-rs/.gitignore
@@ -0,0 +1,2 @@
+target
+Cargo.lock
new file mode 100644
--- /dev/null
+++ b/media/webmidi-rs/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "webmidi"
+version = "0.1.0"
+authors = ["Kyle Machulis <qdot@mozilla.com>"]
+
+[dependencies]
+nsstring = { path = "../../xpcom/rust/nsstring" }
new file mode 100644
--- /dev/null
+++ b/media/webmidi-rs/src/lib.rs
@@ -0,0 +1,116 @@
+#[macro_use]
+extern crate nsstring;
+
+mod platform;
+
+use std::cell::{Cell, RefCell};
+use std::sync::mpsc::{Sender, Receiver};
+use nsstring::{nsStringRepr, nsAString, nsString};
+use std::thread;
+use platform::{run_service, run_test_service};
+
+thread_local!(static MANAGER: RefCell<Option<MIDIServiceManager>> = RefCell::new(None));
+
+#[repr(C)]
+#[allow(non_camel_case_types)]
+struct GeckoMIDIPortInfo {
+    id : nsStringRepr,
+    name : nsStringRepr,
+    manufacturer : nsStringRepr,
+    version : nsStringRepr,
+    port_type : u8
+}
+
+struct MIDIPortInfo {
+    id : String,
+    name : String,
+    manufacturer : String,
+    version : String,
+    port_type : u8
+}
+
+impl MIDIPortInfo {
+    pub fn new(id: String,
+               name: String,
+               manufacturer: String,
+               version: String,
+               port_type: u8) -> MIDIPortInfo {
+        MIDIPortInfo {
+            id: id,
+            name: name,
+            manufacturer: manufacturer,
+            version: version,
+            port_type: port_type
+        }
+    }
+}
+
+pub enum MIDIRequest {
+    GetPortList,
+    SendMessage(String, Vec<u8>),
+    OpenPort(String),
+    ClosePort(String),
+    StopService
+}
+
+struct MIDIServiceManager {
+    // RefCell'd so .join() can consume handle.
+    pub thread: RefCell<Option<thread::JoinHandle<()>>>,
+    pub channel: Sender<MIDIRequest>
+}
+
+#[no_mangle]
+pub unsafe extern fn start_midi_service() {
+    let (tx, rx) = std::sync::mpsc::channel();
+    let thr = thread::spawn(move || {
+        run_test_service(rx);
+    });
+    MANAGER.with(|tm| {
+        let mut t = tm.borrow_mut();
+        *t = Some(MIDIServiceManager {
+            thread: RefCell::new(Some(thr)),
+            channel: tx
+        });
+    });
+}
+
+#[no_mangle]
+pub unsafe extern fn stop_midi_service() {
+    MANAGER.with(|tm| {
+        let mut t = tm.borrow_mut();
+        {
+            let tr = t.as_ref();
+            if let Some(tr) = tr {
+                tr.channel.send(MIDIRequest::StopService).unwrap();
+                // TODO This is possibly going to block whatever thread it's
+                // called from.
+                if let Err(_) = tr.thread.borrow_mut().take().unwrap().join() {
+                    println!("Thread didn't shut down correctly!");
+                }
+            }
+        }
+        *t = None;
+    });
+}
+
+#[link(name = "xul")]
+extern {
+    fn midi_add_port_extern(id : *const nsAString,
+                            name : *const nsAString,
+                            manufacturer : *const nsAString,
+                            version : *const nsAString,
+                            port_type : u8);
+    fn midi_send_port_list_extern();
+    fn midi_send_port_status_extern(id : *const nsAString,
+                                    status: u8);
+}
+
+fn add_port(port: &MIDIPortInfo) {
+    unsafe {
+        midi_add_port_extern(&*nsString::from(&port.id[..]),
+                             &*nsString::from(&port.name[..]),
+                             &*nsString::from(&port.manufacturer[..]),
+                             &*nsString::from(&port.version[..]),
+                             0);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/media/webmidi-rs/src/platform/linux/mod.rs
@@ -0,0 +1,10 @@
+//TODO: Linux Platform Support
+use std::sync::mpsc::Receiver;
+use MIDIRequest;
+
+pub fn run_service(rx: Receiver<MIDIRequest>) {
+    println!("Starting MIDI service thread!");
+    println!("Stopping MIDI service thread!");
+}
+
+
new file mode 100644
--- /dev/null
+++ b/media/webmidi-rs/src/platform/macos/mod.rs
@@ -0,0 +1,1 @@
+// TODO: MacOS Platform Support
new file mode 100644
--- /dev/null
+++ b/media/webmidi-rs/src/platform/mod.rs
@@ -0,0 +1,17 @@
+#[cfg(target_os = "windows")]
+#[path="windows/mod.rs"]
+mod platform;
+
+#[cfg(target_os = "linux")]
+#[path="linux/mod.rs"]
+mod platform;
+
+#[cfg(target_os = "darwin")]
+#[path="macos/mod.rs"]
+mod platform;
+
+#[path="test/mod.rs"]
+mod test_platform;
+
+pub use self::platform::run_service;
+pub use self::test_platform::run_test_service;
new file mode 100644
--- /dev/null
+++ b/media/webmidi-rs/src/platform/test/mod.rs
@@ -0,0 +1,77 @@
+use std::sync::mpsc::{Receiver};
+use std::fmt::Write;
+use {MIDIRequest, MIDIPortInfo};
+use {add_port, midi_send_port_list_extern};
+
+struct MIDITestService {
+    channel: Receiver<MIDIRequest>,
+    control_input_port: MIDIPortInfo,
+    control_output_port: MIDIPortInfo,
+    state_test_input_port: MIDIPortInfo,
+    state_test_output_port: MIDIPortInfo,
+    always_closed_output_port: MIDIPortInfo
+}
+
+impl MIDITestService {
+    pub fn new(rx: Receiver<MIDIRequest>) -> MIDITestService {
+        MIDITestService {
+            channel: rx,
+            control_input_port: MIDIPortInfo::new("b744eebe-f7d8-499b-872b-958f63c8f522".to_string(),
+                                                  "Test Control MIDI Device Input Port".to_string(),
+                                                  "Test Manufacturer".to_string(),
+                                                  "1.0.0".to_string(),
+                                                  0),
+            control_output_port: MIDIPortInfo::new("ab8e7fe8-c4de-436a-a960-30898a7c9a3d".to_string(),
+                                                   "Test Control MIDI Device Output Port".to_string(),
+                                                   "Test Manufacturer".to_string(),
+                                                   "1.0.0".to_string(),
+                                                   1),
+            state_test_input_port: MIDIPortInfo::new("a9329677-8588-4460-a091-9d4a7f629a48".to_string(),
+                                                     "Test State MIDI Device Input Port".to_string(),
+                                                     "Test Manufacturer".to_string(),
+                                                     "1.0.0".to_string(),
+                                                     0),
+            state_test_output_port: MIDIPortInfo::new("478fa225-b5fc-4fa6-a543-d32d9cb651e7".to_string(),
+                                                      "Test State MIDI Device Output Port".to_string(),
+                                                      "Test Manufacturer".to_string(),
+                                                      "1.0.0".to_string(),
+                                                      1),
+            always_closed_output_port: MIDIPortInfo::new("f87d0c76-3c68-49a9-a44f-700f1125c07a".to_string(),
+                                                         "Always Closed MIDI Device Output Port".to_string(),
+                                                         "Test Manufacturer".to_string(),
+                                                         "1.0.0".to_string(),
+                                                         1)
+        }
+    }
+
+    pub fn run_loop(self: &mut MIDITestService) {
+        // Add the default ports when we start the loop.
+        add_port(&self.control_input_port);
+        add_port(&self.control_output_port);
+        add_port(&self.always_closed_output_port);
+        unsafe {
+            midi_send_port_list_extern();
+        }
+        loop {
+            match self.channel.recv().unwrap() {
+                MIDIRequest::GetPortList => {
+                },
+                MIDIRequest::SendMessage(id, msg) => {
+                },
+                MIDIRequest::OpenPort(id) => {
+                },
+                MIDIRequest::ClosePort(id) => {
+                },
+                MIDIRequest::StopService => break
+            }
+        }
+    }
+
+    fn parse_message(self: &mut MIDITestService) {
+    }
+}
+
+pub fn run_test_service(rx: Receiver<MIDIRequest>) {
+    let mut srv = MIDITestService::new(rx);
+    srv.run_loop();
+}
new file mode 100644
--- /dev/null
+++ b/media/webmidi-rs/src/platform/windows/mod.rs
@@ -0,0 +1,1 @@
+// TODO: Windows platform support
--- a/old-configure.in
+++ b/old-configure.in
@@ -3548,16 +3548,17 @@ case "$OS_TARGET" in
        ;;
 esac
 
 MOZ_ARG_DISABLE_BOOL(webmidi,
 [  --disable-webmidi   Disable WebMIDI support],
     MOZ_WEBMIDI=,
     MOZ_WEBMIDI=1)
 
+AC_DEFINE(MOZ_WEBMIDI)
 AC_SUBST(MOZ_WEBMIDI)
 
 dnl ========================================================
 dnl = Breakpad crash reporting (on by default on supported platforms)
 dnl ========================================================
 
 case $target in
 i?86-*-mingw*|x86_64-*-mingw*)
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -13,16 +13,17 @@ version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "gkrust-shared"
 version = "0.1.0"
 dependencies = [
  "mp4parse_capi 0.5.1",
  "nsstring 0.1.0",
+ "webmidi 0.1.0",
 ]
 
 [[package]]
 name = "mp4parse"
 version = "0.5.1"
 dependencies = [
  "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -44,10 +45,17 @@ version = "0.1.0"
 
 [[package]]
 name = "nsstring-gtest"
 version = "0.1.0"
 dependencies = [
  "nsstring 0.1.0",
 ]
 
+[[package]]
+name = "webmidi"
+version = "0.1.0"
+dependencies = [
+ "nsstring 0.1.0",
+]
+
 [metadata]
 "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -11,16 +11,17 @@ version = "0.5.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
 name = "gkrust-shared"
 version = "0.1.0"
 dependencies = [
  "mp4parse_capi 0.5.1",
  "nsstring 0.1.0",
+ "webmidi 0.1.0",
 ]
 
 [[package]]
 name = "mp4parse"
 version = "0.5.1"
 dependencies = [
  "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -31,10 +32,17 @@ version = "0.5.1"
 dependencies = [
  "mp4parse 0.5.1",
 ]
 
 [[package]]
 name = "nsstring"
 version = "0.1.0"
 
+[[package]]
+name = "webmidi"
+version = "0.1.0"
+dependencies = [
+ "nsstring 0.1.0",
+]
+
 [metadata]
 "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
--- a/toolkit/library/rust/shared/Cargo.toml
+++ b/toolkit/library/rust/shared/Cargo.toml
@@ -3,16 +3,17 @@ name = "gkrust-shared"
 version = "0.1.0"
 authors = ["nobody@mozilla.org"]
 license = "MPL-2.0"
 description = "Shared Rust code for libxul"
 
 [dependencies]
 mp4parse_capi = { path = "../../../../media/libstagefright/binding/mp4parse_capi" }
 nsstring = { path = "../../../../xpcom/rust/nsstring" }
+webmidi = { path = "../../../../media/webmidi-rs/" }
 
 [lib]
 path = "lib.rs"
 test = false
 doctest = false
 bench = false
 doc = false
 plugin = false
--- a/toolkit/library/rust/shared/lib.rs
+++ b/toolkit/library/rust/shared/lib.rs
@@ -1,6 +1,7 @@
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 extern crate mp4parse_capi;
 extern crate nsstring;
+extern crate webmidi;