Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/midi/MIDIOutput.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
6
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/TimeStamp.h"
14
#include "mozilla/dom/Performance.h"
15
16
using namespace mozilla;
17
using namespace mozilla::dom;
18
19
MIDIOutput::MIDIOutput(nsPIDOMWindowInner* aWindow, MIDIAccess* aMIDIAccessParent)
20
  : MIDIPort(aWindow, aMIDIAccessParent)
21
0
{
22
0
23
0
}
24
25
//static
26
MIDIOutput*
27
MIDIOutput::Create(nsPIDOMWindowInner* aWindow, MIDIAccess* aMIDIAccessParent,
28
                   const MIDIPortInfo& aPortInfo, const bool aSysexEnabled)
29
0
{
30
0
  MOZ_ASSERT(static_cast<MIDIPortType>(aPortInfo.type()) == MIDIPortType::Output);
31
0
  auto port = new MIDIOutput(aWindow, aMIDIAccessParent);
32
0
  if (NS_WARN_IF(!port->Initialize(aPortInfo, aSysexEnabled))) {
33
0
    return nullptr;
34
0
  }
35
0
  return port;
36
0
}
37
38
JSObject*
39
MIDIOutput::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
40
0
{
41
0
  return MIDIOutput_Binding::Wrap(aCx, this, aGivenProto);
42
0
}
43
44
void
45
MIDIOutput::Send(const Sequence<uint8_t>& aData, const Optional<double>& aTimestamp, ErrorResult& aRv)
46
0
{
47
0
  if (mPort->DeviceState() == MIDIPortDeviceState::Disconnected) {
48
0
    aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
49
0
    return;
50
0
  }
51
0
  // The timestamp passed to us is a DOMHighResTimestamp, which is in relation
52
0
  // to the start of navigation timing. This needs to be turned into a
53
0
  // TimeStamp before it hits the platform specific MIDI service.
54
0
  //
55
0
  // If timestamp is either not set or zero, set timestamp to now and send the
56
0
  // message ASAP.
57
0
  TimeStamp timestamp;
58
0
  if (aTimestamp.WasPassed() && aTimestamp.Value() != 0) {
59
0
    nsCOMPtr<nsIDocument> doc = GetOwner()->GetDoc();
60
0
    if (!doc) {
61
0
      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
62
0
      return;
63
0
    }
64
0
    TimeDuration ts_diff = TimeDuration::FromMilliseconds(aTimestamp.Value());
65
0
    timestamp =
66
0
      GetOwner()->GetPerformance()->GetDOMTiming()->GetNavigationStartTimeStamp() + ts_diff;
67
0
  } else {
68
0
    timestamp = TimeStamp::Now();
69
0
  }
70
0
71
0
  nsTArray<MIDIMessage> msgArray;
72
0
  MIDIUtils::ParseMessages(aData, timestamp, msgArray);
73
0
  // Our translation of the spec is that invalid messages in a multi-message
74
0
  // sequence will be thrown out, but that valid messages will still be used.
75
0
  if (msgArray.IsEmpty()) {
76
0
    aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
77
0
    return;
78
0
  }
79
0
80
0
  // TODO Move this check back to parse message so we don't have to iterate
81
0
  // twice.
82
0
  if (!SysexEnabled()) {
83
0
    for (auto& msg : msgArray) {
84
0
      if (MIDIUtils::IsSysexMessage(msg)) {
85
0
        aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
86
0
        return;
87
0
      }
88
0
    }
89
0
  }
90
0
  mPort->SendSend(msgArray);
91
0
}
92
93
void
94
MIDIOutput::Clear()
95
0
{
96
0
  if (mPort->ConnectionState() == MIDIPortConnectionState::Closed) {
97
0
    return;
98
0
  }
99
0
  mPort->SendClear();
100
0
}