annotate data/osc/OSCQueue.cpp @ 458:f60360209e5c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents 115f60df1e4d
children d7f3dfe6f9a4
rev   line source
Chris@320 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@320 2
Chris@320 3 /*
Chris@320 4 Sonic Visualiser
Chris@320 5 An audio file viewer and annotation editor.
Chris@320 6 Centre for Digital Music, Queen Mary, University of London.
Chris@320 7
Chris@320 8 This program is free software; you can redistribute it and/or
Chris@320 9 modify it under the terms of the GNU General Public License as
Chris@320 10 published by the Free Software Foundation; either version 2 of the
Chris@320 11 License, or (at your option) any later version. See the file
Chris@320 12 COPYING included with this distribution for more information.
Chris@320 13 */
Chris@320 14
Chris@320 15 /*
Chris@320 16 This is a modified version of a source file from the
Chris@320 17 Rosegarden MIDI and audio sequencer and notation editor.
Chris@320 18 This file copyright 2000-2006 Chris Cannam and QMUL.
Chris@320 19 */
Chris@320 20
Chris@320 21 #include "OSCQueue.h"
Chris@320 22
Chris@408 23 #include "base/Profiler.h"
Chris@408 24
Chris@320 25 #include <iostream>
Chris@320 26
Chris@320 27 #define OSC_MESSAGE_QUEUE_SIZE 1023
Chris@320 28
Chris@320 29 #ifdef HAVE_LIBLO
Chris@320 30
Chris@320 31 void
Chris@320 32 OSCQueue::oscError(int num, const char *msg, const char *path)
Chris@320 33 {
Chris@320 34 std::cerr << "ERROR: OSCQueue::oscError: liblo server error " << num
Chris@320 35 << " in path " << path << ": " << msg << std::endl;
Chris@320 36 }
Chris@320 37
Chris@320 38 int
Chris@320 39 OSCQueue::oscMessageHandler(const char *path, const char *types, lo_arg **argv,
Chris@320 40 int argc, lo_message, void *user_data)
Chris@320 41 {
Chris@320 42 OSCQueue *queue = static_cast<OSCQueue *>(user_data);
Chris@320 43
Chris@320 44 int target;
Chris@320 45 int targetData;
Chris@320 46 QString method;
Chris@320 47
Chris@320 48 if (!queue->parseOSCPath(path, target, targetData, method)) {
Chris@320 49 return 1;
Chris@320 50 }
Chris@320 51
Chris@320 52 OSCMessage message;
Chris@320 53 message.setTarget(target);
Chris@320 54 message.setTargetData(targetData);
Chris@320 55 message.setMethod(method);
Chris@320 56
Chris@320 57 int i = 0;
Chris@320 58
Chris@320 59 while (types && i < argc && types[i]) {
Chris@320 60
Chris@320 61 char type = types[i];
Chris@320 62 lo_arg *arg = argv[i];
Chris@320 63
Chris@320 64 switch (type) {
Chris@320 65 case 'i': message.addArg(arg->i); break;
Chris@320 66 // This conversion fails to compile in 64-bit environments
Chris@320 67 // at present, and we don't use the h type anyway so we
Chris@320 68 // can safely omit it
Chris@320 69 // case 'h': message.addArg(arg->h); break;
Chris@320 70 case 'f': message.addArg(arg->f); break;
Chris@320 71 case 'd': message.addArg(arg->d); break;
Chris@320 72 case 'c': message.addArg(arg->c); break;
Chris@320 73 case 't': message.addArg(arg->i); break;
Chris@320 74 case 's': message.addArg(&arg->s); break;
Chris@320 75 default: std::cerr << "WARNING: OSCQueue::oscMessageHandler: "
Chris@320 76 << "Unsupported OSC type '" << type << "'"
Chris@320 77 << std::endl;
Chris@320 78 break;
Chris@320 79 }
Chris@320 80
Chris@320 81 ++i;
Chris@320 82 }
Chris@320 83
Chris@320 84 queue->postMessage(message);
Chris@320 85 return 0;
Chris@320 86 }
Chris@320 87
Chris@320 88 #endif
Chris@320 89
Chris@320 90 OSCQueue::OSCQueue() :
Chris@320 91 #ifdef HAVE_LIBLO
Chris@320 92 m_thread(0),
Chris@320 93 #endif
Chris@320 94 m_buffer(OSC_MESSAGE_QUEUE_SIZE)
Chris@320 95 {
Chris@408 96 Profiler profiler("OSCQueue::OSCQueue");
Chris@408 97
Chris@320 98 #ifdef HAVE_LIBLO
Chris@320 99 m_thread = lo_server_thread_new(NULL, oscError);
Chris@320 100
Chris@320 101 lo_server_thread_add_method(m_thread, NULL, NULL,
Chris@320 102 oscMessageHandler, this);
Chris@320 103
Chris@320 104 lo_server_thread_start(m_thread);
Chris@320 105
Chris@320 106 std::cout << "OSCQueue::OSCQueue: Base OSC URL is "
Chris@320 107 << lo_server_thread_get_url(m_thread) << std::endl;
Chris@320 108 #endif
Chris@320 109 }
Chris@320 110
Chris@320 111 OSCQueue::~OSCQueue()
Chris@320 112 {
Chris@320 113 #ifdef HAVE_LIBLO
Chris@320 114 if (m_thread) {
Chris@320 115 lo_server_thread_stop(m_thread);
Chris@320 116 }
Chris@320 117 #endif
Chris@320 118
Chris@320 119 while (m_buffer.getReadSpace() > 0) {
Chris@320 120 delete m_buffer.readOne();
Chris@320 121 }
Chris@320 122 }
Chris@320 123
Chris@320 124 bool
Chris@320 125 OSCQueue::isOK() const
Chris@320 126 {
Chris@320 127 #ifdef HAVE_LIBLO
Chris@320 128 return (m_thread != 0);
Chris@320 129 #else
Chris@320 130 return false;
Chris@320 131 #endif
Chris@320 132 }
Chris@320 133
Chris@320 134 QString
Chris@320 135 OSCQueue::getOSCURL() const
Chris@320 136 {
Chris@320 137 QString url = "";
Chris@320 138 #ifdef HAVE_LIBLO
Chris@320 139 url = lo_server_thread_get_url(m_thread);
Chris@320 140 #endif
Chris@320 141 return url;
Chris@320 142 }
Chris@320 143
Chris@320 144 size_t
Chris@320 145 OSCQueue::getMessagesAvailable() const
Chris@320 146 {
Chris@320 147 return m_buffer.getReadSpace();
Chris@320 148 }
Chris@320 149
Chris@320 150 OSCMessage
Chris@320 151 OSCQueue::readMessage()
Chris@320 152 {
Chris@320 153 OSCMessage *message = m_buffer.readOne();
Chris@320 154 OSCMessage rmessage = *message;
Chris@320 155 delete message;
Chris@320 156 return rmessage;
Chris@320 157 }
Chris@320 158
Chris@320 159 void
Chris@320 160 OSCQueue::postMessage(OSCMessage message)
Chris@320 161 {
Chris@320 162 int count = 0, max = 5;
Chris@320 163 while (m_buffer.getWriteSpace() == 0) {
Chris@320 164 if (count == max) {
Chris@320 165 std::cerr << "ERROR: OSCQueue::postMessage: OSC message queue is full and not clearing -- abandoning incoming message" << std::endl;
Chris@320 166 return;
Chris@320 167 }
Chris@320 168 std::cerr << "WARNING: OSCQueue::postMessage: OSC message queue (capacity " << m_buffer.getSize() << " is full!" << std::endl;
Chris@320 169 std::cerr << "Waiting for something to be processed" << std::endl;
Chris@320 170 #ifdef _WIN32
Chris@320 171 Sleep(1);
Chris@320 172 #else
Chris@320 173 sleep(1);
Chris@320 174 #endif
Chris@320 175 count++;
Chris@320 176 }
Chris@320 177
Chris@320 178 OSCMessage *mp = new OSCMessage(message);
Chris@320 179 m_buffer.write(&mp, 1);
Chris@320 180 std::cerr << "OSCQueue::postMessage: Posted OSC message: target "
Chris@320 181 << message.getTarget() << ", target data " << message.getTargetData()
Chris@320 182 << ", method " << message.getMethod().toStdString() << std::endl;
Chris@320 183 emit messagesAvailable();
Chris@320 184 }
Chris@320 185
Chris@320 186 bool
Chris@320 187 OSCQueue::parseOSCPath(QString path, int &target, int &targetData,
Chris@320 188 QString &method)
Chris@320 189 {
Chris@320 190 while (path.startsWith("/")) {
Chris@320 191 path = path.right(path.length()-1);
Chris@320 192 }
Chris@320 193
Chris@320 194 int i = 0;
Chris@320 195
Chris@320 196 bool ok = false;
Chris@320 197 target = path.section('/', i, i).toInt(&ok);
Chris@320 198
Chris@320 199 if (!ok) {
Chris@320 200 target = 0;
Chris@320 201 } else {
Chris@320 202 ++i;
Chris@320 203 targetData = path.section('/', i, i).toInt(&ok);
Chris@320 204 if (!ok) {
Chris@320 205 targetData = 0;
Chris@320 206 } else {
Chris@320 207 ++i;
Chris@320 208 }
Chris@320 209 }
Chris@320 210
Chris@320 211 method = path.section('/', i, -1);
Chris@320 212
Chris@320 213 if (method.contains('/')) {
Chris@320 214 std::cerr << "ERROR: OSCQueue::parseOSCPath: malformed path \""
Chris@320 215 << path.toStdString() << "\" (should be target/data/method or "
Chris@320 216 << "target/method or method, where target and data "
Chris@320 217 << "are numeric)" << std::endl;
Chris@320 218 return false;
Chris@320 219 }
Chris@320 220
Chris@320 221 std::cerr << "OSCQueue::parseOSCPath: good path \"" << path.toStdString()
Chris@320 222 << "\"" << std::endl;
Chris@320 223
Chris@320 224 return true;
Chris@320 225 }
Chris@320 226