Permalink
Browse files

Add script that builds and installs BGMApp, BGMDriver and BGMXPCHelper

  • Loading branch information...
1 parent 1672bb8 commit 690d6221d7cf2880d73928653d8bb76fb4730bf7 @kyleneideck committed Apr 5, 2016
Showing with 230 additions and 23 deletions.
  1. +1 −0 .gitignore
  2. +4 −0 BGMApp/BGMApp/BGMXPCListener.mm
  3. +3 −0 BGMDriver/BGMDriver/BGM_XPCHelper.m
  4. +5 −23 README.md
  5. +217 −0 build_and_install.sh
View
@@ -1,6 +1,7 @@
.DS_Store
.*.swp
/BGMDriver/BGMDriver/quick_install.conf
+/build_and_install.log
# Everything below is from https://github.com/github/gitignore/blob/master/Objective-C.gitignore
@@ -59,6 +59,10 @@ - (id) initWithAudioDevices:(BGMAudioDeviceManager*)devices helperConnectionErro
- (void) initHelperConnection {
// Note that this is called when the helper connection's interruption handler is retrying the connection after a timeout.
[self initHelperConnectionWithErrorHandler:^(NSError* error) {
+#if !DEBUG
+ #pragma unused (error)
+#endif
+
DebugMsg("BGMXPCListener::initHelperConnection: Connection error: %s", [[error description] UTF8String]);
}];
}
@@ -87,6 +87,9 @@ UInt64 WaitForBGMAppToStartOutputDevice()
// This remote call to BGMXPCHelper will send a reply when the output device is ready to receive IO. Note that we shouldn't trust
// the reply string.
[[theConnection remoteObjectProxyWithErrorHandler:^(NSError* error) {
+#if !DEBUG
+ #pragma unused (error)
+#endif
DebugMsg("BGM_XPCHelper::WaitForBGMAppToStartOutputDevice: Remote call error: %s",
[[error debugDescription] UTF8String]);
View
@@ -46,30 +46,12 @@ Background Music Device. You can create the aggregate device using the Audio MID
## Install
-No binaries yet, but building only takes a few seconds (as long as you already have Xcode installed).
+No binaries yet, but building should take less than a minute. To build and install everything, clone/download the
+project and run the `build_and_install.sh` script. Unfortunately, **it won't build if you don't have Xcode installed**
+because xcodebuild doesn't work on its own anymore.
-- Install the virtual audio device `Background Music Device.driver` to `/Library/Audio/Plug-Ins/HAL`.
-
- ```shell
- sudo xcodebuild -project BGMDriver/BGMDriver.xcodeproj -target "Background Music Device" RUN_CLANG_STATIC_ANALYZER=0 DSTROOT="/" install
- ```
-- Install the XPC helper.
-
- ```shell
- sudo xcodebuild -project BGMApp/BGMApp.xcodeproj -target BGMXPCHelper RUN_CLANG_STATIC_ANALYZER=0 DSTROOT="/" INSTALL_PATH="$(BGMApp/BGMXPCHelper/safe_install_dir.sh)" install
- ```
-- Install `Background Music.app` to `/Applications` (or wherever).
-
- ```shell
- xcodebuild -project BGMApp/BGMApp.xcodeproj -target "Background Music" RUN_CLANG_STATIC_ANALYZER=0 DSTROOT="/" install
- ```
-- Restart `coreaudiod`: <br>
- (Audio will stop working until the next step, so you might want to pause any running audio apps.)
-
- ```shell
- sudo launchctl kill SIGTERM system/com.apple.audio.coreaudiod
- ```
-- Run `Background Music.app`.
+The script restarts the system audio process (coreaudiod) at the end of the installation, so you might want to pause any
+apps playing audio.
## Uninstall
View
@@ -0,0 +1,217 @@
+#!/bin/bash
+# vim: tw=100:
+
+# This file is part of Background Music.
+#
+# Background Music 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.
+#
+# Background Music 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 Background Music. If not, see <http://www.gnu.org/licenses/>.
+
+#
+# build_and_install.sh
+#
+# Copyright © 2016 Kyle Neideck
+#
+# Builds and installs BGMApp, BGMDriver and BGMXPCHelper. Requires xcodebuild.
+#
+
+# Safe mode
+set -euo pipefail
+IFS=$'\n\t'
+
+# General error message
+set -o errtrace
+general_error() {
+ echo "$(tput setaf 1)ERROR$(tput sgr0): Install script failed at line $1. This is probably a" \
+ "bug in the script. Feel free to report it." >&2
+}
+trap 'general_error ${LINENO}' ERR
+
+# Build for release by default.
+# TODO: Add an option to use the debug configuration?
+CONFIGURATION=Release
+#CONFIGURATION=Debug
+
+# Update .gitignore if you change this.
+LOG_FILE=build_and_install.log
+
+bold_face() {
+ echo $(tput bold)$*$(tput sgr0)
+}
+
+# Takes a PID and returns 0 if the process is running.
+is_alive() {
+ kill -0 $1 > /dev/null 2>&1 && return 0 || return 1
+}
+
+# Shows a "..." animation until the previous command finishes. Shows an error message and exits the
+# script if the command fails.
+#
+# Takes an optional timeout in seconds. The return value will be the exit status of the command.
+show_spinner() {
+ local PREV_COMMAND_PID=$!
+
+ # Get the previous command as a string, with variables resolved. Assumes that if the command has
+ # a child process we just want the text of the child process's command. (And that it only has
+ # one child.)
+ local CHILD_PID=$(pgrep -P ${PREV_COMMAND_PID} | head -n1 || echo ${PREV_COMMAND_PID})
+ local PREV_COMMAND_STRING=$(ps -o command= ${CHILD_PID})
+ local TIMEOUT=${1:-0}
+
+ (I=1;
+ while (is_alive ${PREV_COMMAND_PID}) && ([[ ${TIMEOUT} -lt 1 ]] || [[ $I -lt ${TIMEOUT} ]]); do
+ printf '.';
+ sleep 1;
+ # Erase after we've printed three dots. (\b is backspace.)
+ [[ $(($I % 3)) -eq 0 ]] && printf '\b\b\b \b\b\b';
+ I=$(($I + 1));
+ done) &
+
+ set +e
+ wait ${PREV_COMMAND_PID}
+ local EXIT_STATUS=$?
+ set -e
+
+ # Clean up the dots.
+ printf '\b\b\b'
+
+ # Print an error message if the command fails.
+ # (wait returns 127 if the process has already exited.)
+ if [[ ${EXIT_STATUS} -ne 0 ]] && [[ ${EXIT_STATUS} -ne 127 ]]; then
+ echo "$(tput setaf 1)ERROR$(tput sgr0): Build step failed. See ${LOG_FILE} for details." >&2
+ echo "Failed command:" >&2
+ echo " ${PREV_COMMAND_STRING}" >&2
+
+ exit ${EXIT_STATUS}
+ fi
+
+ return ${EXIT_STATUS}
+}
+
+# Check for xcodebuild.
+if [[ "$(which xcodebuild)" == "" ]]; then
+ echo "$(tput setaf 1)ERROR$(tput sgr0): Can't find xcodebuild in your \$PATH." >&2
+ echo >&2
+ echo "If you have Xcode installed, you should be able to install the command line developer" \
+ "tools, including xcodebuild, with" >&2
+ echo " xcode-select --install" >&2
+ echo "If not, you'll need to install Xcode (~9GB), because xcodebuild no longer works without" \
+ "it." >&2
+
+ # Disable error handlers.
+ trap - ERR
+ set +e
+
+ # Check for Xcode.
+ XCODE_PATH=$(which xcode-select > /dev/null && xcode-select --print-path)
+ XCODE_PATH=${XCODE_PATH%/Contents/Developer}
+
+ if [[ "${XCODE_PATH}" == "" ]] && [[ -d /Applications/Xcode.app ]]; then
+ XCODE_PATH="/Applications/Xcode.app"
+ fi
+
+ if [[ "${XCODE_PATH}" == "" ]] && [[ -d ~/Applications/Xcode.app ]]; then
+ XCODE_PATH="~/Applications/Xcode.app"
+ fi
+
+ if [[ "${XCODE_PATH}" != "" ]]; then
+ echo >&2
+ echo "It looks like you have Xcode installed to ${XCODE_PATH}" >&2
+ fi
+
+ exit 1
+fi
+
+# Go to the project directory.
+cd "$( dirname "${BASH_SOURCE[0]}" )"
+
+# BGMDriver
+
+echo "Installing the virtual audio device $(bold_face Background Music Device.driver) to" \
+ "$(bold_face /Library/Audio/Plug-Ins/HAL)." \
+ | tee ${LOG_FILE}
+
+sudo -v
+
+# Disable the -e shell option here so we can handle the error differently.
+(set +e;
+sudo xcodebuild -project BGMDriver/BGMDriver.xcodeproj \
+ -target "Background Music Device" \
+ -configuration ${CONFIGURATION} \
+ RUN_CLANG_STATIC_ANALYZER=0 \
+ DSTROOT="/" \
+ install >> ${LOG_FILE} 2>&1) &
+
+show_spinner
+
+# BGMXPCHelper
+
+INSTALL_DIR=$(BGMApp/BGMXPCHelper/safe_install_dir.sh)
+
+echo "Installing $(bold_face BGMXPCHelper.xpc) to $(bold_face ${INSTALL_DIR})." \
+ | tee -a ${LOG_FILE}
+
+(set +e;
+sudo xcodebuild -project BGMApp/BGMApp.xcodeproj \
+ -target BGMXPCHelper \
+ -configuration ${CONFIGURATION} \
+ RUN_CLANG_STATIC_ANALYZER=0 \
+ DSTROOT="/" \
+ INSTALL_PATH="${INSTALL_DIR}" \
+ install >> ${LOG_FILE} 2>&1) &
+
+show_spinner
+
+# BGMApp
+
+echo "Installing $(bold_face Background Music.app) to $(bold_face /Applications)." \
+ | tee -a ${LOG_FILE}
+
+(set +e;
+sudo xcodebuild -project BGMApp/BGMApp.xcodeproj \
+ -target "Background Music" \
+ -configuration ${CONFIGURATION} \
+ RUN_CLANG_STATIC_ANALYZER=0 \
+ DSTROOT="/" \
+ install >> ${LOG_FILE} 2>&1) &
+
+show_spinner
+
+# Fix Background Music.app owner/group.
+# (We have to run xcodebuild as root to install BGMXPCHelper because it installs to directories
+# owned by root. But that means the build directory gets created by root, and since BGMApp uses the
+# same build directory we have to run xcodebuild as root to install BGMApp as well.)
+sudo chown -R $(whoami):admin "/Applications/Background Music.app"
+
+# Restart coreaudiod.
+
+echo "Restarting coreaudiod to load BGMDriver." \
+ | tee -a ${LOG_FILE}
+
+sudo launchctl kill SIGTERM system/com.apple.audio.coreaudiod
+
+# Open BGMApp.
+# I'd rather not open BGMApp here, or at least ask first, but you have to change your default audio
+# device after restarting coreaudiod and this is the easiest way.
+echo "Launching Background Music."
+
+open "/Applications/Background Music.app"
+
+# Wait up to 5 seconds for Background Music to start.
+(while [[ "$(ps -u $(whoami) -o ucomm= | grep 'Background Music')" == "" ]]; do
+ sleep 1;
+done) &
+show_spinner 5
+
+echo "Done."
+
+

0 comments on commit 690d622

Please sign in to comment.