[Spice-devel] [PATCH] client: port for Mac OS X
Attila Sukosd
attila.sukosd at gmail.com
Sun Sep 26 05:57:46 PDT 2010
Hi All,
I finally had a bit of time to gather the changes to the spice client in
order to get it working under Mac.
Changes:
- initializing variables so the compiler doesn't complain
- fixed socket flags (MSG_NOSIGNAL => SO_NOSIGPIPE)
- implemented missing pthread_mutex_timedlock()
- replaced clock_gettime with gettimeofday
- added some different headers
- replaced the event handler with a select() based one instead of epoll
- pthread_yield() replaced with pthread_yield_np() for OS X
- disabled clipboard (XConvertSelection), it seem to break things right now
- added initial audio playback using PortAudio (no recording yet, sorry!) +
configure changes to detect OS X and not check for alsa
- force X11 keycodes for OSX instead of evdev
I'm not saying its beautiful, but it does the job :)
- Attila
client/application.cpp | 2 +-
client/client_net_socket.cpp | 7 ++
client/cmd_line_parser.cpp | 8 ++-
client/threads.cpp | 40 +++++++++
client/x11/Makefile.am | 4 +-
client/x11/atomic_count.h | 23 +++--
client/x11/event_sources_p.cpp | 188
++++++++++++++++++++--------------------
client/x11/event_sources_p.h | 42 ++++++---
client/x11/named_pipe.cpp | 2 +-
client/x11/platform.cpp | 33 +++++++-
client/x11/playback.cpp | 80 ++++++++++++++++-
client/x11/playback.h | 11 +++
client/x11/record.cpp | 14 ++-
client/x11/record.h | 4 +
client/x11/red_window.cpp | 4 +-
common/lines.c | 1 +
configure.ac | 31 +++++--
17 files changed, 353 insertions(+), 141 deletions(-)
diff --git a/client/application.cpp b/client/application.cpp
index 490cd8c..7ebeea2 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -648,7 +648,7 @@ RedScreen* Application::get_screen(int id)
if (!(screen = _screens[id])) {
Monitor* mon = find_monitor(id);
SpicePoint size;
-
+ size.x = size.y = 0;
if (_full_screen && mon) {
size = mon->get_size();
} else {
diff --git a/client/client_net_socket.cpp b/client/client_net_socket.cpp
index 6ce44c5..014d5a6 100644
--- a/client/client_net_socket.cpp
+++ b/client/client_net_socket.cpp
@@ -25,6 +25,13 @@
#include <spice/error_codes.h>
#include "utils.h"
+#if defined(__APPLE__) || defined(__MACH__)
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL SO_NOSIGPIPE
+#endif
+#endif
+
+
ClientNetSocket::ClientNetSocket(uint16_t id, const struct in_addr&
dst_addr, uint16_t dst_port,
ProcessLoop& process_loop, EventHandler&
event_handler)
: _id (id)
diff --git a/client/cmd_line_parser.cpp b/client/cmd_line_parser.cpp
index ef72dba..ba0bd5b 100644
--- a/client/cmd_line_parser.cpp
+++ b/client/cmd_line_parser.cpp
@@ -26,6 +26,12 @@
#define DISABLE_ABBREVIATE
+#if defined(__APPLE__) || defined(__MACH__)
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL SO_NOSIGPIPE
+#endif
+#endif
+
CmdLineParser::Option::Option(int in_id, const std::string& in_name, char
in_short_name,
OptionType in_type, const std::string&
in_help,
@@ -450,7 +456,7 @@ void CmdLineParser::show_help()
static const int HELP_WIDTH = 80 - HELP_START_POS;
std::ostringstream os;
- os << basename(_argv[0]) << " - " << _description.c_str() <<
"\n\noptions:\n\n";
+ os << _argv[0] << " - " << _description.c_str() << "\n\noptions:\n\n";
Options::iterator iter = _options.begin();
for (; iter != _options.end(); ++iter) {
diff --git a/client/threads.cpp b/client/threads.cpp
index a9b8ea5..098134a 100644
--- a/client/threads.cpp
+++ b/client/threads.cpp
@@ -21,6 +21,38 @@
#include "debug.h"
#ifdef WIN32
#include <sys/timeb.h>
+#elif defined(__MACH__) || defined(__APPLE__)
+#include <sys/time.h>
+#define _x_min(a, b) ((a) < (b) ? (a) : (b))
+#if _POSIX_TIMERS <= 0
+// FIXME: workaround to missing pthread_mutex_timedlock in Mac OS X
+int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec
*abs_timeout)
+{
+ int pthread_rc;
+ struct timespec remaining, slept, ts;
+
+ remaining = *abs_timeout;
+ while ((pthread_rc = pthread_mutex_trylock(mutex)) == EBUSY) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = (remaining.tv_sec > 0 ? 10000000 :
_x_min(remaining.tv_nsec,10000000));
+ nanosleep(&ts, &slept);
+ ts.tv_nsec -= slept.tv_nsec;
+ if (ts.tv_nsec <= remaining.tv_nsec) {
+ remaining.tv_nsec -= ts.tv_nsec;
+ }
+ else {
+ remaining.tv_sec--;
+ remaining.tv_nsec = (1000000 - (ts.tv_nsec -
remaining.tv_nsec));
+ }
+ if (remaining.tv_sec < 0 || (!remaining.tv_sec && remaining.tv_nsec
<= 0)) {
+ return ETIMEDOUT;
+ }
+ }
+
+ return pthread_rc;
+}
+
+#endif
#endif
Thread::Thread(thread_main_t thread_main, void* opaque)
@@ -43,6 +75,11 @@ static inline void rel_time(struct timespec& time,
uint64_t delta_nano)
_ftime_s(&now);
time.tv_sec = (long)now.time;
time.tv_nsec = now.millitm * 1000 * 1000;
+#elif defined(__APPLE__) || defined(__MACH__)
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+ time.tv_sec = tv.tv_sec;
+ time.tv_nsec = tv.tv_usec*1000;
#else
clock_gettime(CLOCK_MONOTONIC, &time);
#endif
@@ -75,10 +112,13 @@ Condition::Condition()
#else
pthread_condattr_t attr;
pthread_condattr_init(&attr);
+#if defined(__MACH__) || defined(__APPLE__)
+#else
int r;
if ((r = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC))) {
THROW("set clock failed %d", r);
}
+#endif
pthread_cond_init(&_condition, &attr);
pthread_condattr_destroy(&attr);
#endif
diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am
index 101f6dd..ceb07ef 100644
--- a/client/x11/Makefile.am
+++ b/client/x11/Makefile.am
@@ -200,8 +200,10 @@ spicec_LDFLAGS = \
spicec_LDADD = \
$(PIXMAN_LIBS) \
$(ALSA_LIBS) \
+ $(PA_LIBS) \
$(GL_LIBS) \
$(XRANDR_LIBS) \
$(MISC_X_LIBS) \
$(CEGUI_LIBS) \
- -lrt
+ $(LIBRT)
+
diff --git a/client/x11/atomic_count.h b/client/x11/atomic_count.h
index f48c667..8e6fd15 100644
--- a/client/x11/atomic_count.h
+++ b/client/x11/atomic_count.h
@@ -1,23 +1,28 @@
/*
Copyright (C) 2009 Red Hat, Inc.
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
+ 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 2 of
+ the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
+ 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
- Lesser General Public License for more details.
+ 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 Lesser General Public
- License along with this library; if not, see <
http://www.gnu.org/licenses/>.
+ 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 _H_ATOMIC_COUNT
#define _H_ATOMIC_COUNT
+#if defined(__MACH__) || defined(__APPLE__)
+#include <stdint.h>
+#endif
+
+
class AtomicCount {
public:
AtomicCount(uint32_t count = 0) : _count (count) {}
diff --git a/client/x11/event_sources_p.cpp b/client/x11/event_sources_p.cpp
index d59bffd..c164500 100644
--- a/client/x11/event_sources_p.cpp
+++ b/client/x11/event_sources_p.cpp
@@ -1,40 +1,29 @@
/*
Copyright (C) 2009 Red Hat, Inc.
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
+ 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 2 of
+ the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
+ 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
- Lesser General Public License for more details.
+ 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 Lesser General Public
- License along with this library; if not, see <
http://www.gnu.org/licenses/>.
+ 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 <sys/epoll.h>
#include <sys/fcntl.h>
-
#include "event_sources.h"
-#include "debug.h"
-#include "utils.h"
-
-#ifdef USING_EVENT_FD
-#include <sys/eventfd.h>
-#endif
-#define NUM_EPOLL_EVENTS 10
+#include <sys/select.h>
-#ifdef USING_EVENT_FD
-#define WRITE_FD _event_fd
-#define EVENT_DATA_TYPE eventfd_t
-#else
#define WRITE_FD _event_write_fd
#define EVENT_DATA_TYPE uint8_t
-#endif
+
+#include "debug.h"
+#include "utils.h"
class EventWrapper {
public:
@@ -77,9 +66,12 @@ private:
EventSources::EventSources()
{
- _epoll = epoll_create(NUM_EPOLL_EVENTS);
- if (_epoll == -1) {
- THROW("create epool failed");
+ FD_ZERO(&_readfds);
+ FD_ZERO(&_writefds);
+ for(int i=0;i<NUM_EVENTS;i++) {
+ _lofds[i].fd = 0;
+ _lofds[i].fd = NULL;
+ _lofds[i].rw = 0;
}
}
@@ -89,48 +81,82 @@ EventSources::~EventSources()
for (; iter != _events.end(); iter++) {
delete *iter;
}
- close(_epoll);
}
-bool EventSources::wait_events(int timeout_ms)
+bool EventSources::wait_events(int timeout_milli)
{
- struct epoll_event events[NUM_EPOLL_EVENTS];
- int num_events = epoll_wait(_epoll, events, NUM_EPOLL_EVENTS,
timeout_ms);
+ int num_events = 0;
+ struct timeval tmout;
+ tmout.tv_sec = 0;
+ tmout.tv_usec = timeout_milli*1000;
+ fd_set tmpreadfds, tmpwritefds;
+
+ tmpreadfds = _readfds;
+ tmpwritefds = _writefds;
+ if (timeout_milli == -1) {
+ num_events = select(_hfd+1, &tmpreadfds, &tmpwritefds, NULL, NULL);
+ } else {
+ num_events = select(_hfd+1, &tmpreadfds, &tmpwritefds, NULL, &tmout);
+ }
if (num_events == -1) {
- if (errno == EINTR) {
- return false;
- }
- THROW("wait error eventfd failed");
+ //THROW("select() failed");
+ return false;
+ } else if (num_events == 0) {
+ return false;
+ } else {
+ for (int i = 0; i < NUM_EVENTS; i++) {
+ if ((_lofds[i].rw && FD_ISSET(_lofds[i].fd, &tmpwritefds)) ||
+ FD_ISSET(_lofds[i].fd, &tmpreadfds)) {
+ EventWrapper* wrapper;
+ EventSource* event;
+ wrapper = (EventWrapper *)_lofds[i].wrapper;
+ wrapper->ref();
+ if ((event = wrapper->get_event())) {
+ event->action();
+ }
+ wrapper->unref();
+ }
+ }
}
+ return false;
+}
- for (int i = 0; i < num_events; i++) {
- ((EventWrapper*)events[i].data.ptr)->ref();
+void EventSources_p::add_fd(int fd,EventWrapper *wrapper, unsigned char rw)
{
+ // save the highest fd
+ if (fd > _hfd)
+ _hfd = fd;
+ for(int i=0;i<NUM_EVENTS;i++) {
+ if (_lofds[i].fd == 0) {
+ _lofds[i].fd = fd;
+ _lofds[i].wrapper = wrapper;
+ _lofds[i].rw = rw;
+ FD_SET(fd, &_readfds);
+ if (rw)
+ FD_SET(fd, &_writefds);
+ break;
+ }
}
+}
- for (int i = 0; i < num_events; i++) {
- EventWrapper* wrapper;
- EventSource* event;
-
- wrapper = (EventWrapper *)events[i].data.ptr;
- if ((event = wrapper->get_event())) {
- event->action();
- }
- wrapper->unref();
- }
- return false;
+void EventSources_p::del_fd(int fd) {
+ for(int i=0;i<NUM_EVENTS;i++) {
+ if (_lofds[i].fd == fd) {
+ FD_CLR(fd, &_readfds);
+ if (_lofds[i].rw)
+ FD_CLR(fd, &_writefds);
+ _lofds[i].fd = 0;
+ _lofds[i].wrapper = NULL;
+ _lofds[i].rw = 0;
+ }
+ }
}
void EventSources::add_trigger(Trigger& trigger)
{
int fd = trigger.get_fd();
EventWrapper* wrapper = new EventWrapper(*this, trigger);
- struct epoll_event event;
- event.data.ptr = wrapper;
- event.events = EPOLLIN;
- if (epoll_ctl(_epoll, EPOLL_CTL_ADD, fd, &event) == -1) {
- THROW("epoll add failed");
- }
+ add_fd(fd, wrapper, 0);
_events.push_back(wrapper);
}
@@ -162,26 +188,18 @@ void EventSources::remove_trigger(Trigger& trigger)
}
}
int fd = trigger.get_fd();
- if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) {
- THROW("epoll remove failed");
- }
+ del_fd(fd);
}
EventSources::Trigger::Trigger()
{
-#ifdef USING_EVENT_FD
- _event_fd = eventfd(0, 0);
- if (_event_fd == -1) {
- THROW("create eventfd failed");
- }
-#else
int fd[2];
if (pipe(fd) == -1) {
THROW("create pipe failed");
}
_event_fd = fd[0];
_event_write_fd = fd[1];
-#endif
+
int flags;
if ((flags = fcntl(_event_fd, F_GETFL)) == -1) {
THROW("failed to set eventfd non block: %s", strerror(errno));
@@ -195,9 +213,6 @@ EventSources::Trigger::Trigger()
EventSources::Trigger::~Trigger()
{
close(_event_fd);
-#ifndef USING_EVENT_FD
- close(_event_write_fd);
-#endif
}
void EventSources::Trigger::trigger()
@@ -263,25 +278,6 @@ static void set_blocking(int fd)
}
}
-static void add_to_poll(int fd, int epoll, EventWrapper* wrapper)
-{
- struct epoll_event event;
- event.data.ptr = wrapper;
- event.events = EPOLLIN | EPOLLOUT | EPOLLET;
- if (epoll_ctl(epoll, EPOLL_CTL_ADD, fd, &event) == -1) {
- THROW("epoll add failed");
- }
-}
-
-void EventSources::add_socket(Socket& socket)
-{
- int fd = socket.get_socket();
- set_non_blocking(fd);
- EventWrapper* wrapper = new EventWrapper(*this, socket);
- add_to_poll(fd, _epoll, wrapper);
- _events.push_back(wrapper);
-}
-
static bool remove_event(EventSources_p::Events& events, EventSource&
event)
{
EventSources_p::Events::iterator iter = events.begin();
@@ -296,6 +292,15 @@ static bool remove_event(EventSources_p::Events&
events, EventSource& event)
}
}
}
+void EventSources::add_socket(Socket& socket)
+{
+ int fd = socket.get_socket();
+ set_non_blocking(fd);
+ EventWrapper* wrapper = new EventWrapper(*this, socket);
+ add_fd(fd, wrapper, 0); // last parameter should be 1 to monitor for
write availability?
+ _events.push_back(wrapper);
+}
+
void EventSources::remove_socket(Socket& socket)
{
@@ -303,9 +308,7 @@ void EventSources::remove_socket(Socket& socket)
THROW("socket not found");
}
int fd = socket.get_socket();
- if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) {
- THROW("epoll remove failed");
- }
+ del_fd(fd);
set_blocking(fd);
}
@@ -314,7 +317,7 @@ void EventSources::add_file(File& file)
int fd = file.get_fd();
set_non_blocking(fd);
EventWrapper* wrapper = new EventWrapper(*this, file);
- add_to_poll(fd, _epoll, wrapper);
+ add_fd(fd, wrapper, 0);
_events.push_back(wrapper);
}
@@ -324,9 +327,7 @@ void EventSources::remove_file(File& file)
THROW("file not found");
}
int fd = file.get_fd();
- if (epoll_ctl(_epoll, EPOLL_CTL_DEL, fd, NULL) == -1) {
- THROW("epoll remove failed");
- }
+ del_fd(fd);
set_blocking(fd);
}
@@ -337,3 +338,4 @@ void EventSources::add_handle(Handle& file)
void EventSources::remove_handle(Handle& file)
{
}
+
diff --git a/client/x11/event_sources_p.h b/client/x11/event_sources_p.h
index 09703c0..027ac9e 100644
--- a/client/x11/event_sources_p.h
+++ b/client/x11/event_sources_p.h
@@ -1,22 +1,26 @@
/*
Copyright (C) 2009 Red Hat, Inc.
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
+ 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 2 of
+ the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
+ 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
- Lesser General Public License for more details.
+ 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 Lesser General Public
- License along with this library; if not, see <
http://www.gnu.org/licenses/>.
+ 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 _H_EVENT_SOURCES_P
-#define _H_EVENT_SOURCES_P
+#ifndef _H_EVENTS_LOOP_P
+#define _H_EVENTS_LOOP_P
+
+#define NUM_EVENTS 10
+
+#include <sys/select.h>
#include "common.h"
#include "threads.h"
@@ -29,12 +33,24 @@
class EventWrapper;
+struct fd_to_ptr {
+ int fd;
+ EventWrapper *wrapper;
+ unsigned char rw;
+};
+
class EventSources_p {
public:
+ void add_fd(int, EventWrapper*, unsigned char);
+ void del_fd(int);
void remove_wrapper(EventWrapper*);
public:
- int _epoll;
+ int _hfd;
+ fd_set _readfds;
+ fd_set _writefds;
+ struct fd_to_ptr _lofds[NUM_EVENTS];
+
typedef std::list<EventWrapper*> Events;
Events _events;
@@ -49,9 +65,7 @@ public:
public:
int _event_fd;
-#ifndef USING_EVENT_FD
int _event_write_fd;
-#endif
bool _pending_int;
Mutex _lock;
};
diff --git a/client/x11/named_pipe.cpp b/client/x11/named_pipe.cpp
index c6f38da..db3930b 100644
--- a/client/x11/named_pipe.cpp
+++ b/client/x11/named_pipe.cpp
@@ -17,7 +17,7 @@
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/epoll.h>
+//#include <sys/epoll.h>
#include <sys/un.h>
#include "named_pipe.h"
#include "utils.h"
diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index cc1502b..e8d89b0 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -30,15 +30,13 @@
#include <X11/extensions/XShm.h>
#include <unistd.h>
#include <sys/socket.h>
-#include <sys/epoll.h>
+//#include <sys/epoll.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/syscall.h>
-#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <set>
-#include <values.h>
#include <signal.h>
#include <config.h>
#include <sys/shm.h>
@@ -61,6 +59,18 @@
#define BOOL bool
#include "named_pipe.h"
+#if defined(__LINUX__)
+#include <values.h>
+#elif defined(__APPLE__) || defined(__MACH__)
+#include <float.h>
+#include <machine/limits.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <assert.h>
+#define MAXINT INT_MAX
+#define MININT INT_MIN
+#endif
+
//#define X_DEBUG_SYNC(display) XSync(display, False)
#define X_DEBUG_SYNC(display)
#ifdef HAVE_XRANDR12
@@ -427,7 +437,14 @@ void Platform::send_quit_request()
uint64_t Platform::get_monolithic_time()
{
struct timespec time_space;
+#if defined(__LINUX__)
clock_gettime(CLOCK_MONOTONIC, &time_space);
+#elif defined(__APPLE__) || defined(__MACH__)
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ time_space.tv_sec = tv.tv_sec;
+ time_space.tv_nsec = tv.tv_usec*1000;
+#endif
return uint64_t(time_space.tv_sec) * 1000 * 1000 * 1000 +
uint64_t(time_space.tv_nsec);
}
@@ -463,7 +480,11 @@ void Platform::msleep(unsigned int millisec)
void Platform::yield()
{
+#if defined(__APPLE__) || defined(__MACH__)
+ pthread_yield_np();
+#else
pthread_yield();
+#endif
}
void Platform::term_printf(const char* format, ...)
@@ -3016,8 +3037,14 @@ void
Platform::set_clipboard_listener(ClipboardListener* listener)
return;
}
clipboard_listener = listener;
+
+ // FIXME: Tis seems broken on Mac OS X...
+ // Fails with the following error:
+ // 1285496484 ERROR [87445:18446744073709551615] x_error_handler: x
error on display /tmp/launch-h1OMho/org.x:0 error BadWindow (invalid Window
parameter) minor 0 request X_ConvertSelection
+#if !defined(__APPLE__) && !defined(__MACH__)
XConvertSelection(x_display, XA_PRIMARY, utf8_atom, clipboard_prop,
platform_win, CurrentTime);
+#endif
}
bool Platform::set_clipboard_data(uint32_t type, const uint8_t* data,
int32_t size)
diff --git a/client/x11/playback.cpp b/client/x11/playback.cpp
index be89a98..75f1bb0 100644
--- a/client/x11/playback.cpp
+++ b/client/x11/playback.cpp
@@ -22,9 +22,6 @@
#define REING_SIZE_MS 300
WavePlayer::WavePlayer(uint32_t sampels_per_sec, uint32_t bits_per_sample,
uint32_t channels)
- : _pcm (NULL)
- , _hw_params (NULL)
- , _sw_params (NULL)
{
if (!init(sampels_per_sec, bits_per_sample, channels)) {
cleanup();
@@ -34,6 +31,7 @@ WavePlayer::WavePlayer(uint32_t sampels_per_sec, uint32_t
bits_per_sample, uint3
void WavePlayer::cleanup()
{
+#if defined(__LINUX__)
if (_pcm) {
snd_pcm_close(_pcm);
}
@@ -45,6 +43,10 @@ void WavePlayer::cleanup()
if (_sw_params) {
snd_pcm_sw_params_free(_sw_params);
}
+#elif defined(__MACH__) || defined(__APPLE__)
+ Pa_Terminate();
+ _stopped = 1;
+#endif
}
WavePlayer::~WavePlayer()
@@ -57,6 +59,8 @@ bool WavePlayer::init(uint32_t sampels_per_sec,
uint32_t channels)
{
const int frame_size = WavePlaybackAbstract::FRAME_SIZE;
+ _sampels_per_ms = sampels_per_sec / 1000;
+#if defined(__LINUX__)
const char* pcm_device = "default";
snd_pcm_format_t format;
int err;
@@ -71,7 +75,6 @@ bool WavePlayer::init(uint32_t sampels_per_sec,
default:
return false;
}
- _sampels_per_ms = sampels_per_sec / 1000;
if ((err = snd_pcm_open(&_pcm, pcm_device, SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK)) < 0) {
LOG_ERROR("cannot open audio playback device %s %s", pcm_device,
snd_strerror(err));
@@ -174,12 +177,44 @@ bool WavePlayer::init(uint32_t sampels_per_sec,
LOG_ERROR("cannot prepare pcm device %s", snd_strerror(err));
return false;
}
-
+#elif defined(__MACH__) || defined(__APPLE__)
+ _err = Pa_Initialize();
+ if (_err != paNoError) {
+ LOG_ERROR("PortAudio initialization failure!");
+ return false;
+ }
+
+ _outputParameters.device = Pa_GetDefaultOutputDevice();
+ if (_outputParameters.device == paNoDevice) {
+ LOG_ERROR("PortAudio: No dfault output device");
+ return false;
+ }
+ _outputParameters.channelCount = channels;
+ _outputParameters.hostApiSpecificStreamInfo = NULL;
+ switch (bits_per_sample) {
+ case 8:
+ _outputParameters.sampleFormat = paInt8;
+ break;
+ case 16:
+ _outputParameters.sampleFormat = paInt16;
+ break;
+ default:
+ return false;
+ }
+ _outputParameters.suggestedLatency =
Pa_GetDeviceInfo(_outputParameters.device)->defaultLowOutputLatency;
+ _err = Pa_OpenStream(&_stream, NULL, &_outputParameters,
sampels_per_sec, frame_size, paClipOff, NULL, NULL);
+ if (_err != paNoError) {
+ DBG(0,"PortAudio: Error number: %d message: %s", _err,
Pa_GetErrorText(_err));
+ return false;
+ }
+ DBG(0, "Initialized PortAudio: samples/sec: %d channels: %d
bits/sample: %d",sampels_per_sec, channels, bits_per_sample);
+#endif
return true;
}
bool WavePlayer::write(uint8_t* frame)
{
+#if defined(__LINUX__)
snd_pcm_sframes_t ret = snd_pcm_writei(_pcm, frame,
WavePlaybackAbstract::FRAME_SIZE);
if (ret < 0) {
if (ret == -EAGAIN) {
@@ -190,13 +225,43 @@ bool WavePlayer::write(uint8_t* frame)
snd_pcm_writei(_pcm, frame, WavePlaybackAbstract::FRAME_SIZE);
}
}
+#elif defined(__MACH__) || defined(__APPLE__)
+ if (_stopped) {
+ _err = Pa_StartStream(_stream);
+ if (_err) {
+ LOG_ERROR("PortAudio: write errcode: %d message: %s", _err,
Pa_GetErrorText(_err));
+ }
+ _stopped = 0;
+ }
+ _err = Pa_WriteStream(_stream, frame,
WavePlaybackAbstract::FRAME_SIZE);
+ if (_err == paStreamIsStopped) {
+ _err = Pa_StartStream(_stream);
+ _stopped = 0;
+ }
+ // FIXME: error handling?
+ if (_err) {
+// Pa_AbortStream(_stream);
+// Pa_CloseStream(_stream);
+ LOG_ERROR("PortAudio dang: num %d message: %s", _err,
Pa_GetErrorText(_err));
+ } else {
+ //Pa_CloseStream(_stream);
+ }
+#endif
return true;
}
void WavePlayer::stop()
{
+#if defined(__LINUX__)
snd_pcm_drain(_pcm);
snd_pcm_prepare(_pcm);
+#elif defined(__MACH__) || defined(__APPLE__)
+ _err = Pa_StopStream(_stream);
+ if (_err != paNoError) {
+ DBG(0, "PortAudio stop: errcode %d message: %s", _err,
Pa_GetErrorText(_err));
+ }
+ _stopped = 1;
+#endif
}
bool WavePlayer::abort()
@@ -206,6 +271,7 @@ bool WavePlayer::abort()
uint32_t WavePlayer::get_delay_ms()
{
+#if defined(__LINUX__)
ASSERT(_pcm);
snd_pcm_sframes_t delay;
@@ -214,5 +280,9 @@ uint32_t WavePlayer::get_delay_ms()
return 0;
}
return delay / _sampels_per_ms;
+#else
+ // anything more precise than this?
+ return WavePlaybackAbstract::FRAME_SIZE / _sampels_per_ms;
+#endif
}
diff --git a/client/x11/playback.h b/client/x11/playback.h
index d8efd7e..f503ed5 100644
--- a/client/x11/playback.h
+++ b/client/x11/playback.h
@@ -18,7 +18,11 @@
#ifndef _H_LINUX_PLAYBACK
#define _H_LINUX_PLAYBACK
+#if defined(__LINUX__)
#include <alsa/asoundlib.h>
+#elif defined(__MACH__) || defined(__APPLE__)
+#include <portaudio.h>
+#endif
#include "common.h"
#include "audio_devices.h"
@@ -38,9 +42,16 @@ private:
void cleanup();
private:
+#if defined(__LINUX__)
snd_pcm_t* _pcm;
snd_pcm_hw_params_t* _hw_params;
snd_pcm_sw_params_t* _sw_params;
+#elif defined(__MACH__) || defined(__APPLE__)
+ PaStreamParameters _outputParameters;
+ PaStream *_stream;
+ PaError _err;
+ unsigned char _stopped;
+#endif
uint32_t _sampels_per_ms;
};
diff --git a/client/x11/record.cpp b/client/x11/record.cpp
index 4ef9228..77cba4a 100644
--- a/client/x11/record.cpp
+++ b/client/x11/record.cpp
@@ -47,9 +47,6 @@ WaveRecorder::WaveRecorder(Platform::RecordClient& client,
uint32_t bits_per_sample,
uint32_t channels)
: _client (client)
- , _pcm (NULL)
- , _hw_params (NULL)
- , _sw_params (NULL)
, _sample_bytes (bits_per_sample * channels / 8)
, _frame (new uint8_t[_sample_bytes * WaveRecordAbstract::FRAME_SIZE])
, _frame_pos (_frame)
@@ -74,7 +71,7 @@ void WaveRecorder::cleanup()
_client.remove_event_source(*_event_trigger);
delete _event_trigger;
}
-
+#if defined(__LINUX__)
if (_sw_params) {
snd_pcm_sw_params_free(_sw_params);
}
@@ -86,12 +83,14 @@ void WaveRecorder::cleanup()
if (_pcm) {
snd_pcm_close(_pcm);
}
+#endif
}
bool WaveRecorder::init(uint32_t sampels_per_sec,
uint32_t bits_per_sample,
uint32_t channels)
{
+#if defined(__LINUX__)
const int frame_size = WaveRecordAbstract::FRAME_SIZE;
const char* pcm_device = "hw:0,0"; // "default" ???
snd_pcm_format_t format;
@@ -195,21 +194,26 @@ bool WaveRecorder::init(uint32_t sampels_per_sec,
}
_event_trigger = new WaveRecorder::EventTrigger(*this, pfd.fd);
_client.add_event_source(*_event_trigger);
+#endif
return true;
}
void WaveRecorder::start()
{
_frame_pos = _frame;
+#if defined(__LINUX__)
snd_pcm_prepare(_pcm);
snd_pcm_start(_pcm);
snd_pcm_nonblock(_pcm, 1);
+#endif
}
void WaveRecorder::stop()
{
+#if defined(__LINUX__)
snd_pcm_drop(_pcm);
snd_pcm_prepare(_pcm);
+#endif
}
bool WaveRecorder::abort()
@@ -219,6 +223,7 @@ bool WaveRecorder::abort()
void WaveRecorder::on_event()
{
+#if defined(__LINUX__)
for (;;) {
snd_pcm_sframes_t size = (_frame_end - _frame_pos) / _sample_bytes;
size = snd_pcm_readi(_pcm, _frame_pos, size);
@@ -234,5 +239,6 @@ void WaveRecorder::on_event()
_frame_pos = _frame;
}
}
+#endif
}
diff --git a/client/x11/record.h b/client/x11/record.h
index fde58c7..0181b09 100644
--- a/client/x11/record.h
+++ b/client/x11/record.h
@@ -18,7 +18,9 @@
#ifndef _H_LINUX_RECORD
#define _H_LINUX_RECORD
+#if defined(__LINUX__)
#include <alsa/asoundlib.h>
+#endif
#include "common.h"
#include "audio_devices.h"
@@ -45,9 +47,11 @@ private:
private:
Platform::RecordClient& _client;
+#if defined(__LINUX__)
snd_pcm_t* _pcm;
snd_pcm_hw_params_t* _hw_params;
snd_pcm_sw_params_t* _sw_params;
+#endif
uint32_t _sample_bytes;
uint8_t* _frame;
uint8_t* _frame_pos;
diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp
index 5a0886a..c2a0975 100644
--- a/client/x11/red_window.cpp
+++ b/client/x11/red_window.cpp
@@ -55,7 +55,6 @@
static Display* x_display = NULL;
static XContext user_data_context;
-static bool using_evdev = false;
static XIC x_input_context = NULL;
static Atom wm_protocol_atom;
@@ -73,7 +72,10 @@ static Atom wm_user_time;
static RedWindow* focus_window;
static unsigned long focus_serial = 0;
+#ifndef __MACH__ || __APPLE__
#define USE_X11_KEYCODE
+static bool using_evdev = false;
+#endif
#ifdef USE_X11_KEYCODE
diff --git a/common/lines.c b/common/lines.c
index d2e997e..1c67692 100644
--- a/common/lines.c
+++ b/common/lines.c
@@ -2986,6 +2986,7 @@ miWideDashSegment (GCPtr pGC,
double k;
PolyVertexRec vertices[4];
PolyVertexRec saveRight, saveBottom;
+ saveRight.x = saveRight.y = saveBottom.x = saveBottom.y = 0;
PolySlopeRec slopes[4];
PolyEdgeRec left[2], right[2];
LineFaceRec lcapFace, rcapFace;
diff --git a/configure.ac b/configure.ac
index 3369dde..6ef5938 100644
--- a/configure.ac
+++ b/configure.ac
@@ -59,11 +59,16 @@ case "$host" in
esac
AC_MSG_RESULT([$os_win32])
+AC_MSG_CHECKING([for Mac OS X])
case $host in
*-*-linux*)
os_linux=yes
;;
+ *darwin*|*macosx*)
+ os_mac=yes
+ ;;
esac
+AC_MSG_RESULT([$os_mac])
dnl
=========================================================================
dnl Check OS target
@@ -88,7 +93,7 @@ AC_SUBST(red_target)
AM_CONDITIONAL(OS_WIN32, test "$os_win32" = "yes")
AM_CONDITIONAL(OS_UNIX, test "$os_win32" != "yes")
AM_CONDITIONAL(OS_LINUX, test "$os_linux" = "yes")
-
+AM_CONDITIONAL(OS_MAC, test "$os_mac" = "yes")
dnl
=========================================================================
dnl Chek optional features
have_tunnel=no
@@ -119,12 +124,15 @@ AC_SUBST(PROTOCOL_CFLAGS)
AC_CHECK_LIBM
AC_SUBST(LIBM)
-
-AC_CHECK_LIB(rt, clock_gettime,
+if test "x$os_mac" != "yes"; then
+ AC_CHECK_LIB(rt, clock_gettime,
AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Defined if we have clock_gettime()])
LIBRT=-lrt
)
-AC_SUBST(LIBRT)
+ AC_SUBST(LIBRT)
+else
+ LIBRT=""
+fi
SPICE_NONPKGCONFIG_LIBS+=" -pthread $LIBM $LIBRT"
@@ -157,10 +165,17 @@ AC_SUBST(CELT051_LIBS)
AC_SUBST(CELT051_LIBDIR)
SPICE_REQUIRES+=" celt051 >= 0.5.1.1"
-PKG_CHECK_MODULES(ALSA, alsa)
-AC_SUBST(ALSA_CFLAGS)
-AC_SUBST(ALSA_LIBS)
-SPICE_REQUIRES+=" alsa"
+if test "x$os_mac" != "xyes"; then
+ PKG_CHECK_MODULES(ALSA, alsa)
+ AC_SUBST(ALSA_CFLAGS)
+ AC_SUBST(ALSA_LIBS)
+ SPICE_REQUIRES+=" alsa"
+else
+ PKG_CHECK_MODULES(PA, portaudio-2.0 >= 2.0)
+ AC_SUBST(PA_CFLAGS)
+ AC_SUBST(PA_LIBS)
+ SPICE_REQUIRES+=" portaudio-2.0"
+fi
PKG_CHECK_MODULES(SSL, openssl)
AC_SUBST(SSL_CFLAGS)
<http://www.zsuatt.com/>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/spice-devel/attachments/20100926/545a59a7/attachment-0001.html>
More information about the Spice-devel
mailing list