* 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:
parent
7d3b9fd6c3
commit
382a9e1278
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue