3 changed files with 225 additions and 11 deletions
@ -0,0 +1,218 @@ |
|||||
|
/*****************************************************************************
|
||||
|
* darwinvlc.c: the darwin-specific VLC player |
||||
|
***************************************************************************** |
||||
|
* Copyright (C) 1998-2013 the VideoLAN team |
||||
|
* $Id$ |
||||
|
* |
||||
|
* Authors: Vincent Seguin <seguin@via.ecp.fr> |
||||
|
* Samuel Hocevar <sam@zoy.org> |
||||
|
* Gildas Bazin <gbazin@videolan.org> |
||||
|
* Derk-Jan Hartman <hartman at videolan dot org> |
||||
|
* Lots of other people, see the libvlc AUTHORS file |
||||
|
* |
||||
|
* 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 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, write to the Free Software |
||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
||||
|
*****************************************************************************/ |
||||
|
|
||||
|
#ifdef HAVE_CONFIG_H |
||||
|
# include "config.h" |
||||
|
#endif |
||||
|
|
||||
|
#include <vlc/vlc.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <stdbool.h> |
||||
|
#include <string.h> |
||||
|
#include <locale.h> |
||||
|
#include <signal.h> |
||||
|
#ifdef HAVE_PTHREAD_H |
||||
|
# include <pthread.h> |
||||
|
#endif |
||||
|
#include <unistd.h> |
||||
|
|
||||
|
extern void vlc_enable_override (void); |
||||
|
|
||||
|
static bool signal_ignored (int signum) |
||||
|
{ |
||||
|
struct sigaction sa; |
||||
|
|
||||
|
if (sigaction (signum, NULL, &sa)) |
||||
|
return false; |
||||
|
return ((sa.sa_flags & SA_SIGINFO) |
||||
|
? (void *)sa.sa_sigaction : (void *)sa.sa_handler) == SIG_IGN; |
||||
|
} |
||||
|
|
||||
|
static void vlc_kill (void *data) |
||||
|
{ |
||||
|
pthread_t *ps = data; |
||||
|
pthread_kill (*ps, SIGTERM); |
||||
|
} |
||||
|
|
||||
|
static void exit_timeout (int signum) |
||||
|
{ |
||||
|
(void) signum; |
||||
|
signal (SIGINT, SIG_DFL); |
||||
|
} |
||||
|
|
||||
|
/*****************************************************************************
|
||||
|
* main: parse command line, start interface and spawn threads. |
||||
|
*****************************************************************************/ |
||||
|
int main( int i_argc, const char *ppsz_argv[] ) |
||||
|
{ |
||||
|
/* The so-called POSIX-compliant MacOS X reportedly processes SIGPIPE even
|
||||
|
* if it is blocked in all thread. |
||||
|
* Note: this is NOT an excuse for not protecting against SIGPIPE. If |
||||
|
* LibVLC runs outside of VLC, we cannot rely on this code snippet. */ |
||||
|
signal (SIGPIPE, SIG_IGN); |
||||
|
/* Restore SIGCHLD in case our parent process ignores it. */ |
||||
|
signal (SIGCHLD, SIG_DFL); |
||||
|
|
||||
|
#ifndef NDEBUG |
||||
|
/* Activate malloc checking routines to detect heap corruptions. */ |
||||
|
setenv ("MALLOC_CHECK_", "2", 1); |
||||
|
#endif |
||||
|
|
||||
|
#ifdef TOP_BUILDDIR |
||||
|
setenv ("VLC_PLUGIN_PATH", TOP_BUILDDIR"/modules", 1); |
||||
|
setenv ("VLC_DATA_PATH", TOP_SRCDIR"/share", 1); |
||||
|
#endif |
||||
|
|
||||
|
#ifndef ALLOW_RUN_AS_ROOT |
||||
|
if (geteuid () == 0) |
||||
|
{ |
||||
|
fprintf (stderr, "VLC is not supposed to be run as root. Sorry.\n" |
||||
|
"If you need to use real-time priorities and/or privileged TCP ports\n" |
||||
|
"you can use %s-wrapper (make sure it is Set-UID root and\n" |
||||
|
"cannot be run by non-trusted users first).\n", ppsz_argv[0]); |
||||
|
return 1; |
||||
|
} |
||||
|
#endif |
||||
|
|
||||
|
setlocale (LC_ALL, ""); |
||||
|
|
||||
|
if (isatty (STDERR_FILENO)) |
||||
|
/* This message clutters error logs. It is printed only on a TTY.
|
||||
|
* Fortunately, LibVLC prints version info with -vv anyway. */ |
||||
|
fprintf (stderr, "VLC media player %s (revision %s)\n", |
||||
|
libvlc_get_version(), libvlc_get_changeset()); |
||||
|
|
||||
|
sigset_t set; |
||||
|
|
||||
|
sigemptyset (&set); |
||||
|
/* VLC uses sigwait() to dequeue interesting signals.
|
||||
|
* For this to work, those signals must be blocked in all threads, |
||||
|
* including the thread calling sigwait() (see the man page for details). |
||||
|
* |
||||
|
* There are two advantages to sigwait() over traditional signal handlers: |
||||
|
* - delivery is synchronous: no need to worry about async-safety, |
||||
|
* - EINTR is not generated: other threads need not handle that error. |
||||
|
* That being said, some LibVLC programs do not use sigwait(). Therefore |
||||
|
* EINTR must still be handled cleanly, notably from poll() calls. |
||||
|
* |
||||
|
* Signals that request a clean shutdown, and force an unclean shutdown |
||||
|
* if they are triggered again 2+ seconds later. |
||||
|
* We have to handle SIGTERM cleanly because of daemon mode. */ |
||||
|
sigaddset (&set, SIGINT); |
||||
|
sigaddset (&set, SIGHUP); |
||||
|
sigaddset (&set, SIGQUIT); |
||||
|
sigaddset (&set, SIGTERM); |
||||
|
|
||||
|
/* SIGPIPE can happen and would crash the process. On modern systems,
|
||||
|
* the MSG_NOSIGNAL flag protects socket write operations against SIGPIPE. |
||||
|
* But we still need to block SIGPIPE when: |
||||
|
* - writing to pipes, |
||||
|
* - using write() instead of send() for code not specific to sockets. |
||||
|
* LibVLC code assumes that SIGPIPE is blocked. Other LibVLC applications |
||||
|
* shall block it (or handle it somehow) too. |
||||
|
*/ |
||||
|
sigaddset (&set, SIGPIPE); |
||||
|
|
||||
|
/* SIGCHLD must be dequeued to clean up zombie child processes.
|
||||
|
* Furthermore the handler must not be set to SIG_IGN (see above). |
||||
|
* We cannot pragmatically handle EINTR, short reads and short writes |
||||
|
* in every code paths (including underlying libraries). So we just |
||||
|
* block SIGCHLD in all threads, and dequeue it below. */ |
||||
|
sigaddset (&set, SIGCHLD); |
||||
|
|
||||
|
/* Block all these signals */ |
||||
|
pthread_t self = pthread_self (); |
||||
|
pthread_sigmask (SIG_SETMASK, &set, NULL); |
||||
|
|
||||
|
const char *argv[i_argc + 2]; |
||||
|
int argc = 0; |
||||
|
|
||||
|
argv[argc++] = "--no-ignore-config"; |
||||
|
argv[argc++] = "--media-library"; |
||||
|
ppsz_argv++; i_argc--; /* skip executable path */ |
||||
|
|
||||
|
/* When VLC.app is run by double clicking in Mac OS X, the 2nd arg
|
||||
|
* is the PSN - process serial number (a unique PID-ish thingie) |
||||
|
* still ok for real Darwin & when run from command line |
||||
|
* for example -psn_0_9306113 */ |
||||
|
if (i_argc >= 1 && !strncmp (*ppsz_argv, "-psn" , 4)) |
||||
|
ppsz_argv++, i_argc--; |
||||
|
|
||||
|
memcpy (argv + argc, ppsz_argv, i_argc * sizeof (*argv)); |
||||
|
argc += i_argc; |
||||
|
argv[argc] = NULL; |
||||
|
|
||||
|
vlc_enable_override (); |
||||
|
|
||||
|
/* Initialize libvlc */ |
||||
|
libvlc_instance_t *vlc = libvlc_new (argc, argv); |
||||
|
if (vlc == NULL) |
||||
|
return 1; |
||||
|
|
||||
|
int ret = 1; |
||||
|
libvlc_set_exit_handler (vlc, vlc_kill, &self); |
||||
|
libvlc_set_app_id (vlc, "org.VideoLAN.VLC", PACKAGE_VERSION, PACKAGE_NAME); |
||||
|
libvlc_set_user_agent (vlc, "VLC media player", "VLC/"PACKAGE_VERSION); |
||||
|
|
||||
|
libvlc_add_intf (vlc, "hotkeys,none"); |
||||
|
|
||||
|
if (libvlc_add_intf (vlc, NULL)) |
||||
|
goto out; |
||||
|
|
||||
|
libvlc_playlist_play (vlc, -1, 0, NULL); |
||||
|
|
||||
|
/* Qt4 insists on catching SIGCHLD via signal handler. To work around that,
|
||||
|
* unblock it after all our child threads are created. */ |
||||
|
sigdelset (&set, SIGCHLD); |
||||
|
pthread_sigmask (SIG_SETMASK, &set, NULL); |
||||
|
|
||||
|
/* Do not dequeue SIGHUP if it is ignored (nohup) */ |
||||
|
if (signal_ignored (SIGHUP)) |
||||
|
sigdelset (&set, SIGHUP); |
||||
|
/* Ignore SIGPIPE */ |
||||
|
sigdelset (&set, SIGPIPE); |
||||
|
|
||||
|
int signum; |
||||
|
sigwait (&set, &signum); |
||||
|
|
||||
|
/* Restore default signal behaviour after 3 seconds */ |
||||
|
sigemptyset (&set); |
||||
|
sigaddset (&set, SIGINT); |
||||
|
sigaddset (&set, SIGALRM); |
||||
|
signal (SIGINT, SIG_IGN); |
||||
|
signal (SIGALRM, exit_timeout); |
||||
|
pthread_sigmask (SIG_UNBLOCK, &set, NULL); |
||||
|
alarm (3); |
||||
|
|
||||
|
ret = 0; |
||||
|
/* Cleanup */ |
||||
|
out: |
||||
|
libvlc_release (vlc); |
||||
|
|
||||
|
return ret; |
||||
|
} |
||||
Loading…
Reference in new issue