From 382a9e1278fc8c87b62d1349c4000572ff1d14e0 Mon Sep 17 00:00:00 2001 From: Philippe Houdoin Date: Thu, 17 Sep 2009 23:51:19 +0000 Subject: [PATCH] * Any status byte could now break SysEx sequence. We only swallow SysEx end byte (F7) when it's the expected one. Should fix #4445. * Implement device remove handling. Which should fix #4053. Please test it. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@33159 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/midi/DeviceWatcher.cpp | 66 +++++++++++++++----- src/servers/midi/DeviceWatcher.h | 6 ++ src/servers/midi/Jamfile | 4 +- src/servers/midi/PortDrivers.cpp | 98 +++++++++++++++--------------- src/servers/midi/PortDrivers.h | 50 ++++++--------- 5 files changed, 128 insertions(+), 96 deletions(-) diff --git a/src/servers/midi/DeviceWatcher.cpp b/src/servers/midi/DeviceWatcher.cpp index b25a2c2a60..75ac6b3382 100644 --- a/src/servers/midi/DeviceWatcher.cpp +++ b/src/servers/midi/DeviceWatcher.cpp @@ -10,7 +10,6 @@ #include "DeviceWatcher.h" #include "PortDrivers.h" -#include "debug.h" #include #include @@ -20,15 +19,36 @@ #include #include #include - #include +#include +using std::nothrow; + using namespace BPrivate; +using BPrivate::HashMap; +using BPrivate::HashString; + const char *kDevicesRoot = "/dev/midi"; + +class DeviceEndpoints { +public: + DeviceEndpoints(int fd, MidiPortConsumer* consumer, MidiPortProducer* producer) + : fFD(fd), fConsumer(consumer), fProducer(producer) + { + } + + int fFD; + MidiPortConsumer* fConsumer; + MidiPortProducer* fProducer; +}; + + + DeviceWatcher::DeviceWatcher() - : BLooper("MIDI devices watcher") + : BLooper("MIDI devices watcher"), + fDeviceEndpointsMap() { // TODO: add support for vector icons @@ -138,23 +158,29 @@ DeviceWatcher::_ScanDevices(const char* path) void DeviceWatcher::_AddDevice(const char* path) { + if ( fDeviceEndpointsMap.ContainsKey(path) ) + // Already known + return; + int fd = open(path, O_RDWR | O_EXCL); if (fd < 0) return; // printf("DeviceWatcher::_AddDevice(\"%s\");\n", path); - - BMidiEndpoint* endpoint; - endpoint = new MidiPortConsumer(fd, path); - _SetIcons(endpoint); - printf("Register %s MidiPortConsumer\n", endpoint->Name()); - endpoint->Register(); + + MidiPortConsumer* consumer = new MidiPortConsumer(fd, path); + _SetIcons(consumer); + // printf("Register %s MidiPortConsumer\n", consumer->Name()); + consumer->Register(); - endpoint = new MidiPortProducer(fd, path); - _SetIcons(endpoint); - printf("Register %s MidiPortProducer\n", endpoint->Name()); - endpoint->Register(); + MidiPortProducer* producer = new MidiPortProducer(fd, path); + _SetIcons(producer); + // printf("Register %s MidiPortProducer\n", producer->Name()); + producer->Register(); + + DeviceEndpoints * deviceEndpoints = new DeviceEndpoints(fd, consumer, producer); + fDeviceEndpointsMap.Put(path, deviceEndpoints); } @@ -163,7 +189,19 @@ DeviceWatcher::_RemoveDevice(const char* path) { // printf("DeviceWatcher::_RemoveDevice(\"%s\");\n", path); - // TODO: handle device removing + DeviceEndpoints * deviceEndpoints = fDeviceEndpointsMap.Get(path); + if (!deviceEndpoints) + return; + + close(deviceEndpoints->fFD); + + deviceEndpoints->fConsumer->Unregister(); + deviceEndpoints->fProducer->Unregister(); + + delete deviceEndpoints->fConsumer; + delete deviceEndpoints->fProducer; + + fDeviceEndpointsMap.Remove(path); } diff --git a/src/servers/midi/DeviceWatcher.h b/src/servers/midi/DeviceWatcher.h index 4d5f67d436..5c2e374295 100644 --- a/src/servers/midi/DeviceWatcher.h +++ b/src/servers/midi/DeviceWatcher.h @@ -12,9 +12,12 @@ #include +#include "HashMap.h" +#include "HashString.h" class BBitmap; class BMidiEndpoint; +class DeviceEndpoints; class DeviceWatcher : public BLooper { public: @@ -32,6 +35,9 @@ private: void _RemoveDevice(const char* path); void _SetIcons(BMidiEndpoint* endp); + typedef HashMap DeviceEndpointsMap; + DeviceEndpointsMap fDeviceEndpointsMap; + BBitmap* fLargeIcon; BBitmap* fMiniIcon; }; diff --git a/src/servers/midi/Jamfile b/src/servers/midi/Jamfile index c7e075b5e1..33b6c92950 100644 --- a/src/servers/midi/Jamfile +++ b/src/servers/midi/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src servers midi ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders midi storage ; +UsePrivateHeaders midi shared storage ; Server midi_server : MidiServerApp.cpp @@ -12,7 +12,7 @@ Server midi_server : # storage NodeMonitorHandler.cpp - : be midi2 $(TARGET_LIBSTDC++) + : be midi2 libshared.a $(TARGET_LIBSTDC++) : midi_server.rdef ; diff --git a/src/servers/midi/PortDrivers.cpp b/src/servers/midi/PortDrivers.cpp index 2aa17081d5..c6a88d1e54 100644 --- a/src/servers/midi/PortDrivers.cpp +++ b/src/servers/midi/PortDrivers.cpp @@ -1,85 +1,79 @@ /* - * Copyright (c) 2003-2004 Matthijs Hollemans - * Copyright (c) 2004 Christian Packmann - * Copyright (c) 2003 Jerome Leveque + * Copyright 2003-2009, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * Authors: + * Matthijs Hollemans + * Christian Packmann + * Jerome Leveque + * Philippe Houdoin */ +#include "PortDrivers.h" + +#include + #include #include #include -#include "PortDrivers.h" -//------------------------------------------------------------------------------ - -MidiPortConsumer::MidiPortConsumer(int fd_, const char* name = NULL) +MidiPortConsumer::MidiPortConsumer(int fd, const char* name) : BMidiLocalConsumer(name) { - fd = fd_; + fFileDescriptor = fd; } -//------------------------------------------------------------------------------ -void MidiPortConsumer::Data( - uchar* data, size_t length, bool atomic, bigtime_t time) +void +MidiPortConsumer::Data(uchar* data, size_t length, + bool atomic, bigtime_t time) { snooze_until(time - Latency(), B_SYSTEM_TIMEBASE); - if (write(fd, data, length) == -1) - { + if (write(fFileDescriptor, data, length) == -1) { perror("Error sending data to driver"); } } -//------------------------------------------------------------------------------ -MidiPortProducer::MidiPortProducer(int fd_, const char *name = NULL) +// #pragma mark - + + +MidiPortProducer::MidiPortProducer(int fd, const char *name) : BMidiLocalProducer(name) { - fd = fd_; - keepRunning = true; + fFileDescriptor = fd; + fKeepRunning = true; - thread_id thread = spawn_thread( - SpawnThread, "MidiPortProducer", B_URGENT_PRIORITY, this); + BString tmp = name; + tmp << " reader"; + + fReaderThread = spawn_thread( + _ReaderThread, tmp.String(), B_URGENT_PRIORITY, this); - resume_thread(thread); + resume_thread(fReaderThread); } -//------------------------------------------------------------------------------ MidiPortProducer::~MidiPortProducer() { - keepRunning = false; + fKeepRunning = false; + + status_t dummy; + wait_for_thread(fReaderThread, &dummy); } -//------------------------------------------------------------------------------ -int32 MidiPortProducer::SpawnThread(void* data) +int32 +MidiPortProducer::_ReaderThread(void* data) { return ((MidiPortProducer*) data)->GetData(); } -//------------------------------------------------------------------------------ -int32 MidiPortProducer::GetData() +int32 +MidiPortProducer::GetData() { uint8 msgBuf[3]; uint8* sysexBuf = NULL; @@ -95,9 +89,9 @@ int32 MidiPortProducer::GetData() uint8 next = 0; - while (keepRunning) + while (fKeepRunning) { - if (read(fd, &next, 1) != 1) + if (read(fFileDescriptor, &next, 1) != 1) { perror("Error reading data from driver"); if (haveSysEx) @@ -114,14 +108,20 @@ int32 MidiPortProducer::GetData() sysexAlloc *= 2; sysexBuf = (uint8*) realloc(sysexBuf, sysexAlloc); } - } else if (next == B_SYS_EX_END) { - SpraySystemExclusive(sysexBuf, sysexSize); - haveSysEx = false; + continue; } else if ((next & 0xF8) == 0xF8) { // System Realtime interleaved in System Exclusive byte(s) SpraySystemRealTime(next); + continue; + } else { // whatever byte, this one ends the running SysEx sequence + SpraySystemExclusive(sysexBuf, sysexSize); + haveSysEx = false; + if (next == B_SYS_EX_END) + // swallow SysEx end byte + continue; + // any other byte, while ending the SysEx sequence, + // should be handled, not dropped } - continue; } if ((next & 0xF8) == 0xF8) // System Realtime diff --git a/src/servers/midi/PortDrivers.h b/src/servers/midi/PortDrivers.h index ba14af97ec..949b231d46 100644 --- a/src/servers/midi/PortDrivers.h +++ b/src/servers/midi/PortDrivers.h @@ -1,28 +1,14 @@ /* - * Copyright (c) 2003 Matthijs Hollemans - * Copyright (c) 2003 Jerome Leveque + * Copyright 2003-2009, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * Authors: + * Matthijs Hollemans + * Jerome Leveque + * Philippe Houdoin */ - -#ifndef _PORT_DRIVERS_H -#define _PORT_DRIVERS_H +#ifndef PORT_DRIVERS_H +#define PORT_DRIVERS_H #include #include @@ -30,27 +16,29 @@ class MidiPortConsumer : public BMidiLocalConsumer { public: - MidiPortConsumer(int fd, const char* name); + MidiPortConsumer(int fd, const char* path); - virtual void Data(uchar* data, size_t length, bool atomic, bigtime_t time); + void Data(uchar* data, size_t length, bool atomic, bigtime_t time); private: - int fd; + int fFileDescriptor; }; + class MidiPortProducer : public BMidiLocalProducer { public: - MidiPortProducer(int fd, const char* name); + MidiPortProducer(int fd, const char* path = NULL); ~MidiPortProducer(void); - int32 GetData(void); + int32 GetData(void); private: - static int32 SpawnThread(void* data); + static int32 _ReaderThread(void* data); - int fd; - bool keepRunning; + int fFileDescriptor; + volatile bool fKeepRunning; + thread_id fReaderThread; }; -#endif // _PORT_DRIVERS_H +#endif // PORT_DRIVERS_H