Home | History | Annotate | Download | only in midi
      1 // Copyright 2014 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 
      5 #include "media/midi/usb_midi_input_stream.h"
      6 
      7 #include <string.h>
      8 #include <map>
      9 #include <vector>
     10 
     11 #include "base/logging.h"
     12 #include "media/midi/usb_midi_device.h"
     13 #include "media/midi/usb_midi_jack.h"
     14 
     15 namespace media {
     16 
     17 UsbMidiInputStream::JackUniqueKey::JackUniqueKey(UsbMidiDevice* device,
     18                                                  int endpoint_number,
     19                                                  int cable_number)
     20     : device(device),
     21       endpoint_number(endpoint_number),
     22       cable_number(cable_number) {}
     23 
     24 bool UsbMidiInputStream::JackUniqueKey::operator==(
     25     const JackUniqueKey& that) const {
     26   return device == that.device &&
     27       endpoint_number == that.endpoint_number &&
     28       cable_number == that.cable_number;
     29 }
     30 
     31 bool UsbMidiInputStream::JackUniqueKey::operator<(
     32     const JackUniqueKey& that) const {
     33   if (device != that.device)
     34     return device < that.device;
     35   if (endpoint_number != that.endpoint_number)
     36     return endpoint_number < that.endpoint_number;
     37   return cable_number < that.cable_number;
     38 }
     39 
     40 UsbMidiInputStream::UsbMidiInputStream(const std::vector<UsbMidiJack>& jacks,
     41                                        Delegate* delegate)
     42     : delegate_(delegate) {
     43   for (size_t i = 0; i < jacks.size(); ++i) {
     44     jack_dictionary_.insert(
     45         std::make_pair(JackUniqueKey(jacks[i].device,
     46                                      jacks[i].endpoint_number(),
     47                                      jacks[i].cable_number),
     48                        i));
     49   }
     50 }
     51 
     52 UsbMidiInputStream::~UsbMidiInputStream() {}
     53 
     54 void UsbMidiInputStream::OnReceivedData(UsbMidiDevice* device,
     55                                         int endpoint_number,
     56                                         const uint8* data,
     57                                         size_t size,
     58                                         base::TimeTicks time) {
     59   DCHECK_EQ(0u, size % kPacketSize);
     60   size_t current = 0;
     61   while (current + kPacketSize <= size) {
     62     ProcessOnePacket(device, endpoint_number, &data[current], time);
     63     current += kPacketSize;
     64   }
     65 }
     66 
     67 void UsbMidiInputStream::ProcessOnePacket(UsbMidiDevice* device,
     68                                           int endpoint_number,
     69                                           const uint8* packet,
     70                                           base::TimeTicks time) {
     71   // The first 4 bytes of the packet is accessible here.
     72   uint8 code_index = packet[0] & 0x0f;
     73   uint8 cable_number = packet[0] >> 4;
     74   const size_t packet_size_table[16] = {
     75     0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1,
     76   };
     77   size_t packet_size = packet_size_table[code_index];
     78   if (packet_size == 0) {
     79     // These CINs are reserved. Ignore them.
     80     DVLOG(1) << "code index number (" << code_index << ") arrives "
     81              << "but it is reserved.";
     82     return;
     83   }
     84   std::map<JackUniqueKey, size_t>::const_iterator it =
     85       jack_dictionary_.find(JackUniqueKey(device,
     86                                           endpoint_number,
     87                                           cable_number));
     88   if (it != jack_dictionary_.end())
     89     delegate_->OnReceivedData(it->second, &packet[1], packet_size, time);
     90 }
     91 
     92 std::vector<UsbMidiInputStream::JackUniqueKey>
     93 UsbMidiInputStream::RegisteredJackKeysForTesting() const {
     94   std::vector<JackUniqueKey> result(jack_dictionary_.size(),
     95                                     JackUniqueKey(0, 0, 0));
     96   for (std::map<JackUniqueKey, size_t>::const_iterator it =
     97            jack_dictionary_.begin();
     98        it != jack_dictionary_.end(); ++it) {
     99     DCHECK_LT(it->second, result.size());
    100     result[it->second] = it->first;
    101   }
    102   return result;
    103 }
    104 
    105 }  // namespace media
    106