[Spice-devel] [PATCH] client: port for Mac OS X
Hans de Goede
hdegoede at redhat.com
Mon Sep 27 06:58:59 PDT 2010
Hi,
Can you please split this in 3 patches:
1) General apple port stuff
2) epoll -> select changes
3) copyright header fixes
Regards,
Hans
On 09/26/2010 02:57 PM, Attila Sukosd wrote:
> 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 <http://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 <http://configure.ac> b/configure.ac <http://configure.ac>
> index 3369dde..6ef5938 100644
> --- a/configure.ac <http://configure.ac>
> +++ b/configure.ac <http://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/>
>
>
>
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
More information about the Spice-devel
mailing list