* 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
This commit is contained in:
Philippe Houdoin 2009-09-17 23:51:19 +00:00
parent 7d3b9fd6c3
commit 382a9e1278
5 changed files with 128 additions and 96 deletions

View File

@ -10,7 +10,6 @@
#include "DeviceWatcher.h" #include "DeviceWatcher.h"
#include "PortDrivers.h" #include "PortDrivers.h"
#include "debug.h"
#include <Application.h> #include <Application.h>
#include <Bitmap.h> #include <Bitmap.h>
@ -20,15 +19,36 @@
#include <Path.h> #include <Path.h>
#include <Resources.h> #include <Resources.h>
#include <Roster.h> #include <Roster.h>
#include <PathMonitor.h> #include <PathMonitor.h>
#include <new>
using std::nothrow;
using namespace BPrivate; using namespace BPrivate;
using BPrivate::HashMap;
using BPrivate::HashString;
const char *kDevicesRoot = "/dev/midi"; 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() DeviceWatcher::DeviceWatcher()
: BLooper("MIDI devices watcher") : BLooper("MIDI devices watcher"),
fDeviceEndpointsMap()
{ {
// TODO: add support for vector icons // TODO: add support for vector icons
@ -138,23 +158,29 @@ DeviceWatcher::_ScanDevices(const char* path)
void void
DeviceWatcher::_AddDevice(const char* path) DeviceWatcher::_AddDevice(const char* path)
{ {
if ( fDeviceEndpointsMap.ContainsKey(path) )
// Already known
return;
int fd = open(path, O_RDWR | O_EXCL); int fd = open(path, O_RDWR | O_EXCL);
if (fd < 0) if (fd < 0)
return; return;
// printf("DeviceWatcher::_AddDevice(\"%s\");\n", path); // printf("DeviceWatcher::_AddDevice(\"%s\");\n", path);
BMidiEndpoint* endpoint;
endpoint = new MidiPortConsumer(fd, path); MidiPortConsumer* consumer = new MidiPortConsumer(fd, path);
_SetIcons(endpoint); _SetIcons(consumer);
printf("Register %s MidiPortConsumer\n", endpoint->Name()); // printf("Register %s MidiPortConsumer\n", consumer->Name());
endpoint->Register(); consumer->Register();
endpoint = new MidiPortProducer(fd, path); MidiPortProducer* producer = new MidiPortProducer(fd, path);
_SetIcons(endpoint); _SetIcons(producer);
printf("Register %s MidiPortProducer\n", endpoint->Name()); // printf("Register %s MidiPortProducer\n", producer->Name());
endpoint->Register(); 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); // 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);
} }

View File

@ -12,9 +12,12 @@
#include <Looper.h> #include <Looper.h>
#include "HashMap.h"
#include "HashString.h"
class BBitmap; class BBitmap;
class BMidiEndpoint; class BMidiEndpoint;
class DeviceEndpoints;
class DeviceWatcher : public BLooper { class DeviceWatcher : public BLooper {
public: public:
@ -32,6 +35,9 @@ private:
void _RemoveDevice(const char* path); void _RemoveDevice(const char* path);
void _SetIcons(BMidiEndpoint* endp); void _SetIcons(BMidiEndpoint* endp);
typedef HashMap<HashString, DeviceEndpoints*> DeviceEndpointsMap;
DeviceEndpointsMap fDeviceEndpointsMap;
BBitmap* fLargeIcon; BBitmap* fLargeIcon;
BBitmap* fMiniIcon; BBitmap* fMiniIcon;
}; };

View File

@ -2,7 +2,7 @@ SubDir HAIKU_TOP src servers midi ;
SetSubDirSupportedPlatformsBeOSCompatible ; SetSubDirSupportedPlatformsBeOSCompatible ;
UsePrivateHeaders midi storage ; UsePrivateHeaders midi shared storage ;
Server midi_server : Server midi_server :
MidiServerApp.cpp MidiServerApp.cpp
@ -12,7 +12,7 @@ Server midi_server :
# storage # storage
NodeMonitorHandler.cpp NodeMonitorHandler.cpp
: be midi2 $(TARGET_LIBSTDC++) : be midi2 libshared.a $(TARGET_LIBSTDC++)
: midi_server.rdef : midi_server.rdef
; ;

View File

@ -1,85 +1,79 @@
/* /*
* Copyright (c) 2003-2004 Matthijs Hollemans * Copyright 2003-2009, Haiku, Inc. All rights reserved.
* Copyright (c) 2004 Christian Packmann * Distributed under the terms of the MIT License.
* Copyright (c) 2003 Jerome Leveque
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Authors:
* copy of this software and associated documentation files (the "Software"), * Matthijs Hollemans
* to deal in the Software without restriction, including without limitation * Christian Packmann
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * Jerome Leveque
* and/or sell copies of the Software, and to permit persons to whom the * Philippe Houdoin
* 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.
*/ */
#include "PortDrivers.h"
#include <String.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include "PortDrivers.h"
//------------------------------------------------------------------------------ MidiPortConsumer::MidiPortConsumer(int fd, const char* name)
MidiPortConsumer::MidiPortConsumer(int fd_, const char* name = NULL)
: BMidiLocalConsumer(name) : BMidiLocalConsumer(name)
{ {
fd = fd_; fFileDescriptor = fd;
} }
//------------------------------------------------------------------------------
void MidiPortConsumer::Data( void
uchar* data, size_t length, bool atomic, bigtime_t time) MidiPortConsumer::Data(uchar* data, size_t length,
bool atomic, bigtime_t time)
{ {
snooze_until(time - Latency(), B_SYSTEM_TIMEBASE); 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"); 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) : BMidiLocalProducer(name)
{ {
fd = fd_; fFileDescriptor = fd;
keepRunning = true; fKeepRunning = true;
thread_id thread = spawn_thread( BString tmp = name;
SpawnThread, "MidiPortProducer", B_URGENT_PRIORITY, this); tmp << " reader";
resume_thread(thread); fReaderThread = spawn_thread(
_ReaderThread, tmp.String(), B_URGENT_PRIORITY, this);
resume_thread(fReaderThread);
} }
//------------------------------------------------------------------------------
MidiPortProducer::~MidiPortProducer() 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(); return ((MidiPortProducer*) data)->GetData();
} }
//------------------------------------------------------------------------------
int32 MidiPortProducer::GetData() int32
MidiPortProducer::GetData()
{ {
uint8 msgBuf[3]; uint8 msgBuf[3];
uint8* sysexBuf = NULL; uint8* sysexBuf = NULL;
@ -95,9 +89,9 @@ int32 MidiPortProducer::GetData()
uint8 next = 0; 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"); perror("Error reading data from driver");
if (haveSysEx) if (haveSysEx)
@ -114,14 +108,20 @@ int32 MidiPortProducer::GetData()
sysexAlloc *= 2; sysexAlloc *= 2;
sysexBuf = (uint8*) realloc(sysexBuf, sysexAlloc); sysexBuf = (uint8*) realloc(sysexBuf, sysexAlloc);
} }
} else if (next == B_SYS_EX_END) { continue;
SpraySystemExclusive(sysexBuf, sysexSize);
haveSysEx = false;
} else if ((next & 0xF8) == 0xF8) { } else if ((next & 0xF8) == 0xF8) {
// System Realtime interleaved in System Exclusive byte(s) // System Realtime interleaved in System Exclusive byte(s)
SpraySystemRealTime(next); SpraySystemRealTime(next);
}
continue; 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
}
} }
if ((next & 0xF8) == 0xF8) // System Realtime if ((next & 0xF8) == 0xF8) // System Realtime

View File

@ -1,28 +1,14 @@
/* /*
* Copyright (c) 2003 Matthijs Hollemans * Copyright 2003-2009, Haiku, Inc. All rights reserved.
* Copyright (c) 2003 Jerome Leveque * Distributed under the terms of the MIT License.
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Authors:
* copy of this software and associated documentation files (the "Software"), * Matthijs Hollemans
* to deal in the Software without restriction, including without limitation * Jerome Leveque
* the rights to use, copy, modify, merge, publish, distribute, sublicense, * Philippe Houdoin
* 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.
*/ */
#ifndef PORT_DRIVERS_H
#ifndef _PORT_DRIVERS_H #define PORT_DRIVERS_H
#define _PORT_DRIVERS_H
#include <MidiProducer.h> #include <MidiProducer.h>
#include <MidiConsumer.h> #include <MidiConsumer.h>
@ -30,27 +16,29 @@
class MidiPortConsumer : public BMidiLocalConsumer class MidiPortConsumer : public BMidiLocalConsumer
{ {
public: 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: private:
int fd; int fFileDescriptor;
}; };
class MidiPortProducer : public BMidiLocalProducer class MidiPortProducer : public BMidiLocalProducer
{ {
public: public:
MidiPortProducer(int fd, const char* name); MidiPortProducer(int fd, const char* path = NULL);
~MidiPortProducer(void); ~MidiPortProducer(void);
int32 GetData(void); int32 GetData(void);
private: private:
static int32 SpawnThread(void* data); static int32 _ReaderThread(void* data);
int fd; int fFileDescriptor;
bool keepRunning; volatile bool fKeepRunning;
thread_id fReaderThread;
}; };
#endif // _PORT_DRIVERS_H #endif // PORT_DRIVERS_H