Started implementing async for Headset
This commit is contained in:
parent
378efc2d38
commit
bef8044664
4 changed files with 274 additions and 118 deletions
149
src/headset.cpp
149
src/headset.cpp
|
@ -20,147 +20,86 @@
|
|||
|
||||
#include <fstream>
|
||||
#include <errno.h>
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
#include "helper.hpp"
|
||||
#include "raise_exception.hpp"
|
||||
#include "usb_helper.hpp"
|
||||
|
||||
Headset::Headset(libusb_device_handle* handle,
|
||||
bool debug,
|
||||
const std::string& dump_filename,
|
||||
const std::string& play_filename) :
|
||||
bool debug) :
|
||||
m_handle(handle),
|
||||
//m_read_thread(),
|
||||
//m_write_thread(),
|
||||
m_quit_read_thread(false),
|
||||
m_quit_write_thread(false)
|
||||
m_interface(new USBInterface(m_handle, 1)),
|
||||
m_fout(),
|
||||
m_fin()
|
||||
{
|
||||
int ret = libusb_claim_interface(m_handle, 1);
|
||||
|
||||
if (ret != LIBUSB_SUCCESS)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "[headset] " << usb_strerror(ret);
|
||||
throw std::runtime_error(out.str());
|
||||
}
|
||||
|
||||
#ifdef FIXME
|
||||
m_read_thread.reset(new boost::thread(boost::bind(&Headset::read_thread, this, dump_filename, debug)));
|
||||
|
||||
if (!play_filename.empty())
|
||||
{
|
||||
m_write_thread.reset(new boost::thread(boost::bind(&Headset::write_thread, this, play_filename)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Headset::~Headset()
|
||||
{
|
||||
#ifdef FIXME
|
||||
if (m_read_thread.get())
|
||||
m_read_thread->join();
|
||||
|
||||
if (m_write_thread.get())
|
||||
m_write_thread->join();
|
||||
|
||||
m_read_thread.release();
|
||||
m_write_thread.release();
|
||||
#endif
|
||||
|
||||
int ret = libusb_release_interface(m_handle, 1);
|
||||
|
||||
if (ret != LIBUSB_SUCCESS)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "[headset] " << usb_strerror(ret);
|
||||
throw std::runtime_error(out.str());
|
||||
}
|
||||
m_interface.reset();
|
||||
}
|
||||
|
||||
void
|
||||
Headset::write_thread(const std::string& filename)
|
||||
Headset::play_file(const std::string& filename)
|
||||
{
|
||||
std::ifstream in(filename.c_str(), std::ios::binary);
|
||||
m_fin.reset(new std::ifstream(filename.c_str(), std::ios::binary));
|
||||
|
||||
if (!in)
|
||||
if (!*m_fin)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << "[headset] " << filename << ": " << strerror(errno);
|
||||
throw std::runtime_error(out.str());
|
||||
}
|
||||
|
||||
log_info("starting playback: " << filename);
|
||||
|
||||
uint8_t data[32];
|
||||
while(in)
|
||||
{
|
||||
int len = in.read(reinterpret_cast<char*>(data), sizeof(data)).gcount();
|
||||
|
||||
if (len != 32)
|
||||
{
|
||||
// ignore short reads
|
||||
}
|
||||
else
|
||||
{
|
||||
int transferred = 0;
|
||||
const int ret = libusb_interrupt_transfer(m_handle, LIBUSB_ENDPOINT_OUT | 4,
|
||||
data, sizeof(data),
|
||||
&transferred, 0);
|
||||
if (ret != LIBUSB_SUCCESS)
|
||||
{
|
||||
raise_exception(std::runtime_error, "libusb_interrupt_transfer failed: " << usb_strerror(ret));
|
||||
send_data();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_info("finished playback: " << filename);
|
||||
}
|
||||
|
||||
void
|
||||
Headset::read_thread(const std::string& filename, bool debug)
|
||||
Headset::record_file(const std::string& filename)
|
||||
{
|
||||
std::auto_ptr<std::ofstream> out;
|
||||
m_fout.reset(new std::ofstream(filename.c_str(), std::ios::binary));
|
||||
|
||||
if (!filename.empty())
|
||||
{
|
||||
out.reset(new std::ofstream(filename.c_str(), std::ios::binary));
|
||||
|
||||
if (!*out)
|
||||
if (!*m_fout)
|
||||
{
|
||||
raise_exception(std::runtime_error, filename << ": " << strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
while(!m_quit_read_thread)
|
||||
{
|
||||
uint8_t data[32];
|
||||
int len = 0;
|
||||
const int ret = libusb_interrupt_transfer(m_handle, LIBUSB_ENDPOINT_IN | 3,
|
||||
reinterpret_cast<uint8_t*>(data), sizeof(data),
|
||||
&len, 0);
|
||||
if (ret != LIBUSB_SUCCESS)
|
||||
{
|
||||
std::ostringstream outstr;
|
||||
outstr << "[headset] " << usb_strerror(ret);
|
||||
throw std::runtime_error(outstr.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len == 0)
|
||||
{
|
||||
log_debug("-- empty read --");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (out.get())
|
||||
{
|
||||
out->write(reinterpret_cast<char*>(data), sizeof(data));
|
||||
}
|
||||
|
||||
log_debug(raw2str(data, len));
|
||||
}
|
||||
}
|
||||
//FIXME:m_interface->submit_read(3, 32);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Headset::send_data()
|
||||
{
|
||||
uint8_t data[32];
|
||||
int len = m_fin->read(reinterpret_cast<char*>(data), sizeof(data)).gcount();
|
||||
|
||||
if (len != 32)
|
||||
{
|
||||
log_error("short read");
|
||||
}
|
||||
else
|
||||
{
|
||||
//FIXME: m_interface->submit_write(data, 32,
|
||||
// boost::bind(&Headset::send_data, this));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Headset::read_data(uint8_t* data, int len)
|
||||
{
|
||||
if (m_fout.get())
|
||||
{
|
||||
m_fout->write(reinterpret_cast<char*>(data), len);
|
||||
}
|
||||
log_debug(raw2str(data, len));
|
||||
|
||||
//FIXME: m_interface->submit_read(3, 32,
|
||||
// boost::bind(&Headset::send_data, this, _1, _2));
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -22,26 +22,27 @@
|
|||
#include <libusb.h>
|
||||
#include <string>
|
||||
|
||||
#include "usb_interface.hpp"
|
||||
|
||||
class Headset
|
||||
{
|
||||
private:
|
||||
libusb_device_handle* m_handle;
|
||||
//std::auto_ptr<boost::thread> m_read_thread;
|
||||
//std::auto_ptr<boost::thread> m_write_thread;
|
||||
std::auto_ptr<USBInterface> m_interface;
|
||||
|
||||
bool m_quit_read_thread;
|
||||
bool m_quit_write_thread;
|
||||
std::auto_ptr<std::ofstream> m_fout;
|
||||
std::auto_ptr<std::ifstream> m_fin;
|
||||
|
||||
public:
|
||||
Headset(libusb_device_handle* handle,
|
||||
bool debug,
|
||||
const std::string& dump_filename,
|
||||
const std::string& play_filename);
|
||||
Headset(libusb_device_handle* handle, bool debug);
|
||||
~Headset();
|
||||
|
||||
void play_file(const std::string& play_filename);
|
||||
void record_file(const std::string& dump_filename);
|
||||
|
||||
private:
|
||||
void write_thread(const std::string& filename);
|
||||
void read_thread(const std::string& filename, bool debug);
|
||||
void send_data();
|
||||
void read_data(uint8_t* data, int len);
|
||||
|
||||
private:
|
||||
Headset(const Headset&);
|
||||
|
|
149
src/usb_interface.cpp
Normal file
149
src/usb_interface.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
** Xbox360 USB Gamepad Userspace Driver
|
||||
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "usb_interface.hpp"
|
||||
|
||||
#include "raise_exception.hpp"
|
||||
#include "usb_helper.hpp"
|
||||
|
||||
USBInterface::USBInterface(libusb_device_handle* handle, int interface) :
|
||||
m_handle(handle),
|
||||
m_interface(interface),
|
||||
m_endpoints()
|
||||
{
|
||||
int ret = libusb_claim_interface(handle, m_interface);
|
||||
if (ret != LIBUSB_SUCCESS)
|
||||
{
|
||||
raise_exception(std::runtime_error, "error claiming interface: " << interface << ": " << usb_strerror(ret));
|
||||
}
|
||||
}
|
||||
|
||||
USBInterface::~USBInterface()
|
||||
{
|
||||
// cancel all transfer that might still be running
|
||||
for(Endpoints::iterator it = m_endpoints.begin(); it != m_endpoints.end(); ++it)
|
||||
{
|
||||
if (it->second)
|
||||
{
|
||||
libusb_cancel_transfer(it->second);
|
||||
libusb_free_transfer(it->second);
|
||||
}
|
||||
}
|
||||
m_endpoints.clear();
|
||||
|
||||
libusb_release_interface(m_handle, m_interface);
|
||||
}
|
||||
|
||||
void
|
||||
USBInterface::submit_read(int endpoint, int len,
|
||||
const boost::function<void (uint8_t, int)>& callback)
|
||||
{
|
||||
assert(m_endpoints.find(endpoint) == m_endpoints.end());
|
||||
|
||||
libusb_transfer* transfer = libusb_alloc_transfer(0);
|
||||
|
||||
uint8_t* data = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * len));
|
||||
transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
|
||||
libusb_fill_interrupt_transfer(transfer, m_handle,
|
||||
endpoint | LIBUSB_ENDPOINT_IN,
|
||||
data, len,
|
||||
&USBInterface::on_read_data_wrap, this,
|
||||
0); // timeout
|
||||
int ret;
|
||||
ret = libusb_submit_transfer(transfer);
|
||||
if (ret != LIBUSB_SUCCESS)
|
||||
{
|
||||
libusb_free_transfer(transfer);
|
||||
raise_exception(std::runtime_error, "libusb_submit_transfer(): " << usb_strerror(ret));
|
||||
}
|
||||
else
|
||||
{
|
||||
// transfer is send on its way, so store it
|
||||
m_endpoints[endpoint | LIBUSB_ENDPOINT_IN] = transfer;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
USBInterface::submit_write(int endpoint, uint8_t* data_in, int len)
|
||||
{
|
||||
libusb_transfer* transfer = libusb_alloc_transfer(0);
|
||||
transfer->flags |= LIBUSB_TRANSFER_FREE_BUFFER;
|
||||
transfer->flags |= LIBUSB_TRANSFER_FREE_TRANSFER;
|
||||
|
||||
// copy data into a newly allocated buffer
|
||||
uint8_t* data = static_cast<uint8_t*>(malloc(sizeof(uint8_t) * len));
|
||||
memcpy(data, data_in, len);
|
||||
|
||||
libusb_fill_interrupt_transfer(transfer, m_handle,
|
||||
endpoint | LIBUSB_ENDPOINT_OUT,
|
||||
data, len,
|
||||
&USBInterface::on_write_data_wrap, this,
|
||||
0); // timeout
|
||||
|
||||
int ret;
|
||||
ret = libusb_submit_transfer(transfer);
|
||||
if (ret != LIBUSB_SUCCESS)
|
||||
{
|
||||
libusb_free_transfer(transfer);
|
||||
raise_exception(std::runtime_error, "libusb_submit_transfer(): " << usb_strerror(ret));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_endpoints[endpoint | LIBUSB_ENDPOINT_OUT] = transfer;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
USBInterface::cancel_transfer(int endpoint)
|
||||
{
|
||||
Endpoints::iterator it = m_endpoints.find(endpoint);
|
||||
if (it == m_endpoints.end())
|
||||
{
|
||||
raise_exception(std::runtime_error, "endpoint " << (endpoint & LIBUSB_ENDPOINT_ADDRESS_MASK) << "not found");
|
||||
}
|
||||
else
|
||||
{
|
||||
libusb_cancel_transfer(it->second);
|
||||
libusb_free_transfer(it->second);
|
||||
m_endpoints.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
USBInterface::cancel_read(int endpoint)
|
||||
{
|
||||
cancel_transfer(endpoint | LIBUSB_ENDPOINT_IN);
|
||||
}
|
||||
|
||||
void
|
||||
USBInterface::cancel_write(int endpoint)
|
||||
{
|
||||
cancel_transfer(endpoint | LIBUSB_ENDPOINT_OUT);
|
||||
}
|
||||
|
||||
void
|
||||
USBInterface::on_read_data(libusb_transfer *transfer)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
USBInterface::on_write_data(libusb_transfer *transfer)
|
||||
{
|
||||
}
|
||||
|
||||
/* EOF */
|
67
src/usb_interface.hpp
Normal file
67
src/usb_interface.hpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
** Xbox360 USB Gamepad Userspace Driver
|
||||
** Copyright (C) 2011 Ingo Ruhnke <grumbel@gmx.de>
|
||||
**
|
||||
** This program is free software: you can redistribute it and/or modify
|
||||
** it under the terms of the GNU General Public License as published by
|
||||
** the Free Software Foundation, either version 3 of the License, or
|
||||
** (at your option) any later version.
|
||||
**
|
||||
** This program is distributed in the hope that it will be useful,
|
||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
** GNU General Public License for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef HEADER_XBOXDRV_USB_INTERFACE_HPP
|
||||
#define HEADER_XBOXDRV_USB_INTERFACE_HPP
|
||||
|
||||
#include <libusb.h>
|
||||
#include <boost/function.hpp>
|
||||
#include <map>
|
||||
|
||||
class USBInterface
|
||||
{
|
||||
private:
|
||||
libusb_device_handle* m_handle;
|
||||
int m_interface;
|
||||
typedef std::map<int, libusb_transfer*> Endpoints;
|
||||
Endpoints m_endpoints;
|
||||
|
||||
public:
|
||||
USBInterface(libusb_device_handle* handle, int interface);
|
||||
~USBInterface();
|
||||
|
||||
void submit_read(int endpoint, int len,
|
||||
const boost::function<void (uint8_t, int)>& callback);
|
||||
void cancel_read(int endpoint);
|
||||
|
||||
void submit_write(int endpoint, uint8_t* data, int len);
|
||||
void cancel_write(int endpoint);
|
||||
|
||||
private:
|
||||
void cancel_transfer(int endpoint);
|
||||
|
||||
void on_read_data(libusb_transfer *transfer);
|
||||
static void on_read_data_wrap(libusb_transfer *transfer)
|
||||
{
|
||||
static_cast<USBInterface*>(transfer->user_data)->on_read_data(transfer);
|
||||
}
|
||||
|
||||
void on_write_data(libusb_transfer *transfer);
|
||||
static void on_write_data_wrap(libusb_transfer *transfer)
|
||||
{
|
||||
static_cast<USBInterface*>(transfer->user_data)->on_write_data(transfer);
|
||||
}
|
||||
|
||||
private:
|
||||
USBInterface(const USBInterface&);
|
||||
USBInterface& operator=(const USBInterface&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* EOF */
|
Loading…
Reference in a new issue