midi_manager_mac_unittest.cc 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "media/midi/midi_manager_mac.h"
  5. #include <CoreMIDI/MIDIServices.h>
  6. #include <stddef.h>
  7. #include <stdint.h>
  8. #include <memory>
  9. #include "base/run_loop.h"
  10. #include "base/synchronization/lock.h"
  11. #include "base/test/task_environment.h"
  12. #include "media/midi/midi_service.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. namespace midi {
  15. namespace {
  16. using mojom::PortState;
  17. using mojom::Result;
  18. void Noop(const MIDIPacketList*, void*, void*) {}
  19. class FakeMidiManagerClient : public MidiManagerClient {
  20. public:
  21. FakeMidiManagerClient()
  22. : result_(Result::NOT_SUPPORTED),
  23. wait_for_result_(true),
  24. wait_for_port_(true),
  25. unexpected_callback_(false) {}
  26. FakeMidiManagerClient(const FakeMidiManagerClient&) = delete;
  27. FakeMidiManagerClient& operator=(const FakeMidiManagerClient&) = delete;
  28. // MidiManagerClient implementation.
  29. void AddInputPort(const mojom::PortInfo& info) override {}
  30. void AddOutputPort(const mojom::PortInfo& info) override {
  31. base::AutoLock lock(lock_);
  32. // AddOutputPort may be called before CompleteStartSession() is invoked
  33. // if one or more MIDI devices including virtual ports are connected.
  34. // Just ignore in such cases.
  35. if (wait_for_result_)
  36. return;
  37. // Check if this is the first call after CompleteStartSession(), and
  38. // the case should not happen twice.
  39. if (!wait_for_port_)
  40. unexpected_callback_ = true;
  41. info_ = info;
  42. wait_for_port_ = false;
  43. }
  44. void SetInputPortState(uint32_t port_index, PortState state) override {}
  45. void SetOutputPortState(uint32_t port_index, PortState state) override {}
  46. void CompleteStartSession(Result result) override {
  47. base::AutoLock lock(lock_);
  48. if (!wait_for_result_)
  49. unexpected_callback_ = true;
  50. result_ = result;
  51. wait_for_result_ = false;
  52. }
  53. void ReceiveMidiData(uint32_t port_index,
  54. const uint8_t* data,
  55. size_t size,
  56. base::TimeTicks timestamp) override {}
  57. void AccumulateMidiBytesSent(size_t size) override {}
  58. void Detach() override {}
  59. bool GetWaitForResult() {
  60. base::AutoLock lock(lock_);
  61. return wait_for_result_;
  62. }
  63. bool GetWaitForPort() {
  64. base::AutoLock lock(lock_);
  65. return wait_for_port_;
  66. }
  67. Result WaitForResult() {
  68. while (GetWaitForResult()) {
  69. base::RunLoop run_loop;
  70. run_loop.RunUntilIdle();
  71. }
  72. EXPECT_FALSE(unexpected_callback_);
  73. return result_;
  74. }
  75. mojom::PortInfo WaitForPort() {
  76. while (GetWaitForPort()) {
  77. base::RunLoop run_loop;
  78. run_loop.RunUntilIdle();
  79. }
  80. EXPECT_FALSE(unexpected_callback_);
  81. return info_;
  82. }
  83. private:
  84. base::Lock lock_;
  85. Result result_;
  86. bool wait_for_result_;
  87. mojom::PortInfo info_;
  88. bool wait_for_port_;
  89. bool unexpected_callback_;
  90. };
  91. class MidiManagerMacTest : public ::testing::Test {
  92. public:
  93. MidiManagerMacTest() : service_(std::make_unique<MidiService>()) {}
  94. MidiManagerMacTest(const MidiManagerMacTest&) = delete;
  95. MidiManagerMacTest& operator=(const MidiManagerMacTest&) = delete;
  96. ~MidiManagerMacTest() override {
  97. service_->Shutdown();
  98. base::RunLoop run_loop;
  99. run_loop.RunUntilIdle();
  100. }
  101. protected:
  102. void StartSession(MidiManagerClient* client) {
  103. service_->StartSession(client);
  104. }
  105. void EndSession(MidiManagerClient* client) { service_->EndSession(client); }
  106. private:
  107. std::unique_ptr<MidiService> service_;
  108. base::test::SingleThreadTaskEnvironment task_environment_;
  109. };
  110. TEST_F(MidiManagerMacTest, MidiNotification) {
  111. std::unique_ptr<FakeMidiManagerClient> client(new FakeMidiManagerClient);
  112. StartSession(client.get());
  113. Result result = client->WaitForResult();
  114. EXPECT_EQ(Result::OK, result);
  115. // Create MIDIClient, and MIDIEndpoint as a MIDIDestination. This should
  116. // notify MIDIManagerMac as a MIDIObjectAddRemoveNotification.
  117. MIDIClientRef midi_client = 0;
  118. OSStatus status = MIDIClientCreate(
  119. CFSTR("MidiManagerMacTest"), nullptr, nullptr, &midi_client);
  120. EXPECT_EQ(noErr, status);
  121. MIDIEndpointRef ep = 0;
  122. status = MIDIDestinationCreate(
  123. midi_client, CFSTR("DestinationTest"), Noop, nullptr, &ep);
  124. EXPECT_EQ(noErr, status);
  125. SInt32 id;
  126. status = MIDIObjectGetIntegerProperty(ep, kMIDIPropertyUniqueID, &id);
  127. EXPECT_EQ(noErr, status);
  128. EXPECT_NE(0, id);
  129. // Wait until the created device is notified to MidiManagerMac.
  130. mojom::PortInfo info = client->WaitForPort();
  131. EXPECT_EQ("DestinationTest", info.name);
  132. EndSession(client.get());
  133. if (ep)
  134. MIDIEndpointDispose(ep);
  135. if (midi_client)
  136. MIDIClientDispose(midi_client);
  137. }
  138. } // namespace
  139. } // namespace midi