Bug 1880216 - Migrate Fenix docs into Sphinx. r=owlish,geckoview-reviewers,android...
[gecko.git] / dom / midi / MIDIOutput.cpp
blob3cdd7d308d5ad0e52306431efbf6e9cc891e3269
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/MIDIOutput.h"
8 #include "mozilla/dom/MIDIPortChild.h"
9 #include "mozilla/dom/MIDITypes.h"
10 #include "mozilla/dom/MIDIOutputBinding.h"
11 #include "mozilla/dom/MIDIUtils.h"
12 #include "nsDOMNavigationTiming.h"
13 #include "mozilla/ErrorResult.h"
14 #include "mozilla/TimeStamp.h"
15 #include "mozilla/dom/Document.h"
16 #include "mozilla/dom/Performance.h"
18 using namespace mozilla;
19 using namespace mozilla::dom;
21 MIDIOutput::MIDIOutput(nsPIDOMWindowInner* aWindow) : MIDIPort(aWindow) {}
23 // static
24 RefPtr<MIDIOutput> MIDIOutput::Create(nsPIDOMWindowInner* aWindow,
25 MIDIAccess* aMIDIAccessParent,
26 const MIDIPortInfo& aPortInfo,
27 const bool aSysexEnabled) {
28 MOZ_ASSERT(static_cast<MIDIPortType>(aPortInfo.type()) ==
29 MIDIPortType::Output);
30 RefPtr<MIDIOutput> port = new MIDIOutput(aWindow);
31 if (NS_WARN_IF(
32 !port->Initialize(aPortInfo, aSysexEnabled, aMIDIAccessParent))) {
33 return nullptr;
35 return port;
38 JSObject* MIDIOutput::WrapObject(JSContext* aCx,
39 JS::Handle<JSObject*> aGivenProto) {
40 return MIDIOutput_Binding::Wrap(aCx, this, aGivenProto);
43 void MIDIOutput::Send(const Sequence<uint8_t>& aData,
44 const Optional<double>& aTimestamp, ErrorResult& aRv) {
45 if (Port()->DeviceState() == MIDIPortDeviceState::Disconnected) {
46 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
47 return;
49 // The timestamp passed to us is a DOMHighResTimestamp, which is in relation
50 // to the start of navigation timing. This needs to be turned into a
51 // TimeStamp before it hits the platform specific MIDI service.
53 // If timestamp is either not set or zero, set timestamp to now and send the
54 // message ASAP.
55 TimeStamp timestamp;
56 if (aTimestamp.WasPassed() && aTimestamp.Value() != 0) {
57 nsCOMPtr<Document> doc = GetOwner()->GetDoc();
58 if (!doc) {
59 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
60 return;
62 TimeDuration ts_diff = TimeDuration::FromMilliseconds(aTimestamp.Value());
63 timestamp = GetOwner()
64 ->GetPerformance()
65 ->GetDOMTiming()
66 ->GetNavigationStartTimeStamp() +
67 ts_diff;
68 } else {
69 timestamp = TimeStamp::Now();
72 nsTArray<MIDIMessage> msgArray;
73 bool ret = MIDIUtils::ParseMessages(aData, timestamp, msgArray);
74 if (!ret) {
75 aRv.ThrowTypeError("Invalid MIDI message");
76 return;
79 if (msgArray.IsEmpty()) {
80 aRv.ThrowTypeError("Empty message array");
81 return;
84 // TODO Move this check back to parse message so we don't have to iterate
85 // twice.
86 if (!SysexEnabled()) {
87 for (auto& msg : msgArray) {
88 if (MIDIUtils::IsSysexMessage(msg)) {
89 aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
90 return;
94 Port()->SendSend(msgArray);
97 void MIDIOutput::Clear() {
98 if (Port()->ConnectionState() == MIDIPortConnectionState::Closed) {
99 return;
101 Port()->SendClear();