* 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 "PortDrivers.h"
#include "debug.h"
#include <Application.h>
#include <Bitmap.h>
@ -20,15 +19,36 @@
#include <Path.h>
#include <Resources.h>
#include <Roster.h>
#include <PathMonitor.h>
#include <new>
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);
}

View File

@ -12,9 +12,12 @@
#include <Looper.h>
#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<HashString, DeviceEndpoints*> DeviceEndpointsMap;
DeviceEndpointsMap fDeviceEndpointsMap;
BBitmap* fLargeIcon;
BBitmap* fMiniIcon;
};

View File

@ -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
;

View File

@ -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 <String.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#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";
resume_thread(thread);
fReaderThread = spawn_thread(
_ReaderThread, tmp.String(), B_URGENT_PRIORITY, this);
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

View File

@ -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 <MidiProducer.h>
#include <MidiConsumer.h>
@ -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