Compare commits

..
601 changed files with 40446 additions and 98408 deletions

View file

@ -1,48 +0,0 @@
---
name: Bug report
about: Follow the troubleshooting guide before reporting a bug
---
**READ ME FIRST!**
If you're here because something basic is not working (like gamepad input, video, or similar), it's probably something specific to your setup, so make sure you've gone through the Troubleshooting Guide first: https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting
If you still have trouble with basic functionality after following the guide, join our Discord server where there are many other volunteers who can help (or direct you back here if it looks like a Moonlight bug after all). https://moonlight-stream.org/discord
**Describe the bug**
A clear and concise description of what the bug is.
**Steps to reproduce**
Any special steps that are required for the bug to appear.
**Screenshots**
If applicable, add screenshots to help explain your problem. If the issue is related to video glitching or poor quality, please include screenshots.
**Affected games**
List the games you've tried that exhibit the issue. To see if the issue is game-specific, try streaming Steam Big Picture with Moonlight and see if the issue persists there.
**Other Moonlight clients**
- Does the issue occur when using Moonlight on PC or Android?
**Moonlight settings (please complete the following information)**
- Have any settings been adjusted from defaults?
- If so, which settings have been changed?
- Does the problem still occur after reverting settings back to default?
**Gamepad-related issues (please complete if problem is gamepad-related)**
- Do you have any gamepads connected to your host PC directly?
- If gamepad input is not working, does it work if you use Moonlight's on-screen controls?
- Does the problem still remain if you stream the desktop and use https://html5gamepad.com to test your gamepad?
- Instructions for streaming the desktop can be found here: https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide
**Device details (please complete the following information)**
- iOS/tvOS version: [e.g. iOS 14.2]
- Device model: [e.g. iPhone 11 Pro]
**Server PC details (please complete the following information)**
- OS: [e.g. Windows 10 1809]
- GeForce Experience version: [e.g. 3.16.0.140]
- Nvidia GPU driver: [e.g. 417.35]
- Antivirus and firewall software: [e.g. Windows Defender and Windows Firewall]
**Additional context**
Anything else you think may be relevant to the issue or special about your specific setup.

View file

@ -1 +0,0 @@
blank_issues_enabled: false

View file

@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View file

@ -1,4 +0,0 @@
issuesOpened: >
If this is a question about Moonlight or you need help troubleshooting a streaming problem, please use the help channels on our [Discord server](https://moonlight-stream.org/discord) instead of GitHub issues. There are many more people available on Discord to help you and answer your questions.<br /><br />
This issue tracker should only be used for specific bugs or feature requests.<br /><br />
Thank you, and happy streaming!

25
.github/lock.yml vendored
View file

@ -1,25 +0,0 @@
# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 60
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: false
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels:
- enhancement
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: >
This issue has been automatically locked since there has not been
any recent activity after it was closed. If you experience an issue
that looks similar to this one, please open a new issue with details
about your specific streaming setup.
# Don't lock PRs
only: issues

View file

@ -1,8 +0,0 @@
# ProBot No Response (https://probot.github.io/apps/no-response/)
daysUntilClose: 7
responseRequiredLabel: 'need more info'
closeComment: >
This issue has been automatically closed because there was no response to a
request for more information from the issue opener. Please leave a comment or
open a new issue if you have additional information related to this issue.

14
.github/stale.yml vendored
View file

@ -1,14 +0,0 @@
# ProBot Stale (https://probot.github.io/apps/stale/)
daysUntilStale: 90
daysUntilClose: 7
exemptLabels:
- accepted
- bug
- enhancement
- meta
staleLabel: stale
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs.
closeComment: false

View file

@ -1,45 +0,0 @@
name: CI
on:
push:
pull_request:
branches:
- master
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
build:
name: Build (${{ matrix.platform }})
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
include:
- scheme: Moonlight
sdk: iphonesimulator
platform: iOS
- scheme: Moonlight TV
sdk: appletvsimulator
platform: tvOS
steps:
- name: Checkout
uses: actions/checkout@v7
with:
submodules: recursive
- name: Download ${{ matrix.platform }} platform
run: xcodebuild -downloadPlatform ${{ matrix.platform }}
- name: Build Debug
run: xcodebuild -project Moonlight.xcodeproj -scheme "${{ matrix.scheme }}" -configuration Debug -sdk ${{ matrix.sdk }} clean build
- name: Build Release
run: xcodebuild -project Moonlight.xcodeproj -scheme "${{ matrix.scheme }}" -configuration Release -sdk ${{ matrix.sdk }} clean build

2
.gitignore vendored
View file

@ -1,6 +1,4 @@
**/xcuserdata/
**/Moonlight.xcscmblueprint
**/xcschemes/*.xcscheme
.DS_Store
Build
DerivedData

3
.gitmodules vendored
View file

@ -1,6 +1,3 @@
[submodule "moonlight-common/moonlight-common-c"]
path = moonlight-common/moonlight-common-c
url = https://github.com/moonlight-stream/moonlight-common-c.git
[submodule "X1Kit"]
path = X1Kit
url = https://github.com/cgutman/X1Kit.git

144
BuildScripts/Opus/build.sh Executable file
View file

@ -0,0 +1,144 @@
#!/bin/bash
set -e
source config.sh
# Number of CPUs (for make -j)
NCPU=`sysctl -n hw.ncpu`
if test x$NJOB = x; then
NJOB=$NCPU
fi
PLATFORMBASE=$(xcode-select -print-path)"/Platforms"
SCRIPT_DIR=$( (cd -P $(dirname $0) && pwd) )
DIST_DIR_BASE=${DIST_DIR_BASE:="$SCRIPT_DIR/dist"}
if [ ! -d opus ]
then
echo "opus source directory does not exist, run sync.sh"
fi
# PATH=${SCRIPT_DIR}/gas-preprocessor/:$PATH
for ARCH in $ARCHS
do
OPUS_DIR=opus-$ARCH
if [ ! -d $OPUS_DIR ]
then
echo "Directory $OPUS_DIR does not exist, run sync.sh"
exit 1
fi
echo "Compiling source for $ARCH in directory $OPUS_DIR"
echo "cd $OPUS_DIR"
cd $OPUS_DIR
DIST_DIR=$DIST_DIR_BASE-$ARCH
echo "mkdir -p $DIST_DIR"
mkdir -p $DIST_DIR
CFLAGS_ARCH=$ARCH
case $ARCH in
armv7)
EXTRA_FLAGS="--with-pic --enable-fixed-point"
EXTRA_CFLAGS="-mcpu=cortex-a8 -mfpu=neon -miphoneos-version-min=7.1"
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
IOSSDK=iPhoneOS
;;
armv7s)
EXTRA_FLAGS="--with-pic --enable-fixed-point"
EXTRA_CFLAGS="-mcpu=cortex-a9 -mfpu=neon -miphoneos-version-min=7.1"
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
IOSSDK=iPhoneOS
;;
aarch64)
CFLAGS_ARCH="arm64"
EXTRA_FLAGS="--with-pic --enable-fixed-point"
EXTRA_CFLAGS="-miphoneos-version-min=7.1"
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
IOSSDK=iPhoneOS
;;
x86_64)
EXTRA_FLAGS="--with-pic"
EXTRA_CFLAGS="-miphoneos-version-min=7.1"
PLATFORM="${PLATFORMBASE}/iPhoneSimulator.platform"
IOSSDK=iPhoneSimulator
;;
i386)
EXTRA_FLAGS="--with-pic"
EXTRA_CFLAGS="-miphoneos-version-min=7.1"
PLATFORM="${PLATFORMBASE}/iPhoneSimulator.platform"
IOSSDK=iPhoneSimulator
;;
*)
echo "Unsupported architecture ${ARCH}"
exit 1
;;
esac
echo "Configuring opus for $ARCH..."
echo "./autogen.sh"
./autogen.sh
CFLAGS="-g -O2 -pipe -arch ${CFLAGS_ARCH} \
-isysroot ${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk \
-I${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk/usr/include \
${EXTRA_CFLAGS}"
LDFLAGS="-arch ${CFLAGS_ARCH} \
-isysroot ${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk \
-L${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk/usr/lib"
echo "CFLAGS=$CFLAGS"
echo "LDFLAGS=$LDFLAGS"
export CFLAGS
export LDFLAGS
export CXXCPP="/usr/bin/cpp"
export CPP="$CXXCPP"
export CXX="/usr/bin/gcc"
export CC="/usr/bin/gcc"
export LD="/usr/bin/ld"
export AR="/usr/bin/ar"
export AS="/usr/bin/ls"
export NM="/usr/bin/nm"
export RANLIB="/usr/bin/ranlib"
export STRIP="/usr/bin/strip"
echo "./configure \
--prefix=$DIST_DIR \
--host=${ARCH}-apple-darwin \
--with-sysroot=${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk \
--enable-static=yes \
--enable-shared=no \
--disable-doc \
${EXTRA_FLAGS}"
./configure \
--prefix=$DIST_DIR \
--host=${ARCH}-apple-darwin \
--with-sysroot=${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk \
--enable-static=yes \
--enable-shared=no \
--disable-doc \
${EXTRA_FLAGS}
echo "Installing opus for $ARCH..."
echo "make clean"
make clean
echo "make -j$NJOB V=1"
make -j$NJOB V=1
echo "make install"
make install
echo "cd $SCRIPT_DIR"
cd $SCRIPT_DIR
if [ -d $DIST_DIR/bin ]
then
rm -rf $DIST_DIR/bin
fi
if [ -d $DIST_DIR/share ]
then
rm -rf $DIST_DIR/share
fi
done

51
BuildScripts/Opus/combine.sh Executable file
View file

@ -0,0 +1,51 @@
#!/bin/bash
set -e
source config.sh
for ARCH in $ARCHS
do
if [ -d dist-$ARCH ]
then
MAIN_ARCH=$ARCH
fi
done
if [ -z "$MAIN_ARCH" ]
then
echo "Please compile an architecture"
exit 1
fi
OUTPUT_DIR="dist-uarch"
rm -rf $OUTPUT_DIR
mkdir -p $OUTPUT_DIR/lib $OUTPUT_DIR/include
for LIB in dist-$MAIN_ARCH/lib/*.a
do
LIB=`basename $LIB`
LIPO_CREATE=""
for ARCH in $ARCHS
do
LIPO_ARCH=$ARCH
if [ "$ARCH" = "aarch64" ];
then
LIPO_ARCH="arm64"
fi
if [ -d dist-$ARCH ]
then
LIPO_CREATE="$LIPO_CREATE-arch $LIPO_ARCH dist-$ARCH/lib/$LIB "
fi
done
OUTPUT="$OUTPUT_DIR/lib/$LIB"
echo "Creating: $OUTPUT"
xcrun -sdk iphoneos lipo -create $LIPO_CREATE -output $OUTPUT
xcrun -sdk iphoneos lipo -info $OUTPUT
done
echo "Copying headers from dist-$MAIN_ARCH..."
cp -R dist-$MAIN_ARCH/include/* $OUTPUT_DIR/include

36
BuildScripts/Opus/config.sh Executable file
View file

@ -0,0 +1,36 @@
#!/bin/bash
OPUS_DIR="opus"
IOSSDK_VER=8.1
ARCHS="armv7 armv7s aarch64 i386 x86_64"
remove_arch() {
OLD_ARCHS="$ARCHS"
NEW_ARCHS=""
REMOVAL="$1"
for ARCH in $OLD_ARCHS; do
if [ "$ARCH" != "$REMOVAL" ] ; then
NEW_ARCHS="$NEW_ARCHS $ARCH"
fi
done
ARCHS=$NEW_ARCHS
}
# armv7s is only supported in iOS 6.0+
CHECK=`echo $IOSSDK_VER '>= 6.0' | bc -l`
if [ "$CHECK" = "0" ] ; then
remove_arch "armv7s"
fi
# armv6 is not supported any more since iOS 6.0
CHECK=`echo $IOSSDK_VER '< 6.0' | bc -l`
if [ "$CHECK" = "0" ] ; then
remove_arch "armv6"
fi
echo 'Architectures to build:' $ARCHS

20
BuildScripts/Opus/sync.sh Executable file
View file

@ -0,0 +1,20 @@
#!/bin/sh
set -e
source config.sh
SCRIPT_DIR=$( (cd -P $(dirname $0) && pwd) )
DIST_DIR_BASE=${DIST_DIR_BASE:="$SCRIPT_DIR/dist"}
cd opus
git checkout master
git pull origin master
cd ..
for ARCH in $ARCHS
do
OPUS_DIR=opus-$ARCH
echo "Syncing source for $ARCH to directory $OPUS_DIR"
rsync opus/ $OPUS_DIR/ --exclude '.*' -a --delete
done

104
BuildScripts/build-ffmpeg.sh Executable file
View file

@ -0,0 +1,104 @@
#!/bin/bash
SYSROOT_iPHONE="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk"
SYSROOT_SIMULATOR="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk"
CC_IPHONE="xcrun -sdk iphoneos clang"
CC_SIMULATOR="xcrun -sdk iphonesimulator clang"
function build_one {
./configure \
--prefix=$PREFIX \
--disable-ffmpeg \
--disable-ffplay \
--disable-ffprobe \
--disable-ffserver \
--disable-armv5te \
--disable-armv6 \
--disable-doc \
--disable-everything \
--disable-debug \
--enable-decoder=h264 \
--enable-avresample \
--enable-cross-compile \
--sysroot=$SYSROOT \
--target-os=darwin \
--cc="$CC" \
--extra-cflags="$CFLAGS" \
--extra-ldflags="$LDFLAGS" \
--enable-pic \
$ADDI_FLAGS
make clean && make -j4 && make install
}
# armv7
function build_armv7 {
PREFIX="armv7"
SYSROOT=$SYSROOT_iPHONE
CC=$CC_IPHONE
CFLAGS="-arch armv7 -mfpu=neon -miphoneos-version-min=7.1 -fpic"
LDFLAGS="-arch armv7 -isysroot $SYSROOT_iPHONE -miphoneos-version-min=7.1"
ADDI_FLAGS="--arch=arm --cpu=cortex-a9"
build_one
}
# armv7s
function build_armv7s {
PREFIX="armv7s"
SYSROOT=$SYSROOT_iPHONE
CC=$CC_IPHONE
CFLAGS="-arch armv7s -mfpu=neon -miphoneos-version-min=7.1"
LDFLAGS="-arch armv7s -isysroot $SYSROOT_iPHONE -miphoneos-version-min=7.1"
ADDI_FLAGS="--arch=arm --cpu=cortex-a9"
build_one
}
# i386
function build_i386 {
PREFIX="i386"
SYSROOT=$SYSROOT_SIMULATOR
CC=$CC_SIMULATOR
CFLAGS="-arch i386"
LDFLAGS="-arch i386 -isysroot $SYSROOT_SIMULATOR -mios-simulator-version-min=7.1"
ADDI_FLAGS="--arch=i386 --cpu=i386 --disable-asm"
build_one
}
# create fat library
function build_universal {
cd armv7/lib
for file in *.a
do
cd ../..
xcrun -sdk iphoneos lipo -output universal/lib/$file -create \
-arch armv7 armv7/lib/$file \
-arch armv7s armv7s/lib/$file \
-arch i386 i386/lib/$file
echo "Universal $file created."
cd -
done
cd ../..
}
echo "FFmpeg directory?"
read SOURCE
cd $SOURCE
if [ "$1" = "clean" ]
then
rm -r armv7 armv7s i386 universal
make clean
exit 0
fi
mkdir armv7
mkdir armv7s
mkdir i386
mkdir -p universal/lib
build_armv7
build_armv7s
build_i386
build_universal
echo "Ouput files in $SOURCE/armv7 $SOURCE/armv7s $SOURCE/i386 $SOURCE/universal"

View file

@ -1,180 +0,0 @@
#!/bin/bash
# Builds libopus for iOS or tvOS.
#
# Copyright 2012 Mike Tigas <mike@tig.as>
#
# Based on work by Felix Schulze on 16.12.10.
# Copyright 2010 Felix Schulze. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
###########################################################################
# Choose your libopus version and your currently-installed iOS SDK version:
#
TARGET="AppleTV" # "iPhone"
VERSION="1.3.1"
SDKVERSION="16.1"
MINVERSIONDEF="-mtvos-version-min=12.0" # "-miphoneos-version-min=12.0"
###########################################################################
#
# Don't change anything under this line!
#
###########################################################################
# by default, we won't build for debugging purposes
if [ "${DEBUG}" == "true" ]; then
echo "Compiling for debugging ..."
OPT_CFLAGS="-O0 -fno-inline -g"
OPT_LDFLAGS=""
OPT_CONFIG_ARGS="--enable-assertions --disable-asm"
else
OPT_CFLAGS="-O3 -g"
OPT_LDFLAGS=""
OPT_CONFIG_ARGS=""
fi
# No need to change this since xcode build will only compile in the
# necessary bits from the libraries we create
ARCHS="x86_64 arm64"
DEVELOPER=`xcode-select -print-path`
#DEVELOPER="/Applications/Xcode.app/Contents/Developer"
cd "`dirname \"$0\"`"
REPOROOT=$(pwd)
# Where we'll end up storing things in the end
OUTPUTDIR="${REPOROOT}/dependencies"
mkdir -p ${OUTPUTDIR}/include
mkdir -p ${OUTPUTDIR}/lib
BUILDDIR="${REPOROOT}/build"
# where we will keep our sources and build from.
SRCDIR="${BUILDDIR}/src"
mkdir -p $SRCDIR
# where we will store intermediary builds
INTERDIR="${BUILDDIR}/built"
mkdir -p $INTERDIR
########################################
cd $SRCDIR
# Exit the script if an error happens
set -e
if [ ! -e "${SRCDIR}/opus-${VERSION}.tar.gz" ]; then
echo "Downloading opus-${VERSION}.tar.gz"
curl -LO http://downloads.xiph.org/releases/opus/opus-${VERSION}.tar.gz
fi
echo "Using opus-${VERSION}.tar.gz"
tar zxf opus-${VERSION}.tar.gz -C $SRCDIR
cd "${SRCDIR}/opus-${VERSION}"
set +e # don't bail out of bash script if ccache doesn't exist
CCACHE=`which ccache`
if [ $? == "0" ]; then
echo "Building with ccache: $CCACHE"
CCACHE="${CCACHE} "
else
echo "Building without ccache"
CCACHE=""
fi
set -e # back to regular "bail out on error" mode
export ORIGINALPATH=$PATH
for ARCH in ${ARCHS}
do
if [ "${ARCH}" == "i386" ] || [ "${ARCH}" == "x86_64" ]; then
PLATFORM="${TARGET}Simulator"
EXTRA_CFLAGS="-arch ${ARCH}"
EXTRA_CONFIG="--host=x86_64-apple-darwin"
else
PLATFORM="${TARGET}OS"
EXTRA_CFLAGS="-arch ${ARCH}"
EXTRA_CONFIG="--host=arm-apple-darwin"
fi
mkdir -p "${INTERDIR}/${PLATFORM}${SDKVERSION}-${ARCH}.sdk"
./configure --disable-shared --enable-static --with-pic --disable-extra-programs --disable-doc ${EXTRA_CONFIG} \
--prefix="${INTERDIR}/${PLATFORM}${SDKVERSION}-${ARCH}.sdk" \
LDFLAGS="$LDFLAGS ${OPT_LDFLAGS} -fPIE ${MINVERSIONDEF} -L${OUTPUTDIR}/lib" \
CFLAGS="$CFLAGS ${EXTRA_CFLAGS} ${OPT_CFLAGS} -fPIE ${MINVERSIONDEF} -I${OUTPUTDIR}/include -isysroot ${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer/SDKs/${PLATFORM}${SDKVERSION}.sdk" \
# Build the application and install it to the fake SDK intermediary dir
# we have set up. Make sure to clean up afterward because we will re-use
# this source tree to cross-compile other targets.
make -j$(nproc)
make install
make clean
done
########################################
echo "Build library..."
# These are the libs that comprise libopus.
OUTPUT_LIBS="libopus.a"
for OUTPUT_LIB in ${OUTPUT_LIBS}; do
INPUT_LIBS=""
for ARCH in ${ARCHS}; do
if [ "${ARCH}" == "i386" ] || [ "${ARCH}" == "x86_64" ];
then
PLATFORM="${TARGET}Simulator"
else
PLATFORM="${TARGET}OS"
fi
INPUT_ARCH_LIB="${INTERDIR}/${PLATFORM}${SDKVERSION}-${ARCH}.sdk/lib/${OUTPUT_LIB}"
if [ -e $INPUT_ARCH_LIB ]; then
INPUT_LIBS="${INPUT_LIBS} ${INPUT_ARCH_LIB}"
fi
done
# Combine the three architectures into a universal library.
if [ -n "$INPUT_LIBS" ]; then
lipo -create $INPUT_LIBS \
-output "${OUTPUTDIR}/lib/${OUTPUT_LIB}"
else
echo "$OUTPUT_LIB does not exist, skipping (are the dependencies installed?)"
fi
done
for ARCH in ${ARCHS}; do
if [ "${ARCH}" == "i386" ] || [ "${ARCH}" == "x86_64" ];
then
PLATFORM="${TARGET}Simulator"
else
PLATFORM="${TARGET}OS"
fi
cp -R ${INTERDIR}/${PLATFORM}${SDKVERSION}-${ARCH}.sdk/include/* ${OUTPUTDIR}/include/
if [ $? == "0" ]; then
# We only need to copy the headers over once. (So break out of forloop
# once we get first success.)
break
fi
done
####################
echo "Building done."
echo "Cleaning up..."
rm -fr ${INTERDIR}
rm -fr "${SRCDIR}/opus-${VERSION}"
echo "Done."

124
BuildScripts/build-openssl.sh Executable file
View file

@ -0,0 +1,124 @@
#!/bin/bash
# Yay shell scripting! This script builds a static version of
# OpenSSL ${OPENSSL_VERSION} for iOS 7.0 that contains code for
# armv6, armv7, arm7s and i386.
#set -x
# Setup paths to stuff we need
OPENSSL_VERSION="1.0.1h"
DEVELOPER="/Applications/Xcode.app/Contents/Developer"
SDK_VERSION="7.1"
MIN_VERSION="7.1"
IPHONEOS_PLATFORM="${DEVELOPER}/Platforms/iPhoneOS.platform"
IPHONEOS_SDK="${IPHONEOS_PLATFORM}/Developer/SDKs/iPhoneOS.sdk"
IPHONEOS_GCC="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang"
IPHONESIMULATOR_PLATFORM="${DEVELOPER}/Platforms/iPhoneSimulator.platform"
IPHONESIMULATOR_SDK="${IPHONESIMULATOR_PLATFORM}/Developer/SDKs/iPhoneSimulator.sdk"
IPHONESIMULATOR_GCC="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang"
# Make sure things actually exist
if [ ! -d "$IPHONEOS_PLATFORM" ]; then
echo "Cannot find $IPHONEOS_PLATFORM"
exit 1
fi
if [ ! -d "$IPHONEOS_SDK" ]; then
echo "Cannot find $IPHONEOS_SDK"
exit 1
fi
if [ ! -x "$IPHONEOS_GCC" ]; then
echo "Cannot find $IPHONEOS_GCC"
exit 1
fi
if [ ! -d "$IPHONESIMULATOR_PLATFORM" ]; then
echo "Cannot find $IPHONESIMULATOR_PLATFORM"
exit 1
fi
if [ ! -d "$IPHONESIMULATOR_SDK" ]; then
echo "Cannot find $IPHONESIMULATOR_SDK"
exit 1
fi
if [ ! -x "$IPHONESIMULATOR_GCC" ]; then
echo "Cannot find $IPHONESIMULATOR_GCC"
exit 1
fi
# Clean up whatever was left from our previous build
rm -rf include lib
rm -rf /tmp/openssl-${OPENSSL_VERSION}-*
rm -rf /tmp/openssl-${OPENSSL_VERSION}-*.*-log
build()
{
TARGET=$1
ARCH=$2
GCC=$3
SDK=$4
EXTRA=$5
rm -rf "openssl-${OPENSSL_VERSION}"
tar xfz "openssl-${OPENSSL_VERSION}.tar.gz"
pushd .
cd "openssl-${OPENSSL_VERSION}"
./Configure ${TARGET} --openssldir="/tmp/openssl-${OPENSSL_VERSION}-${ARCH}" ${EXTRA} &> "/tmp/openssl-${OPENSSL_VERSION}-${ARCH}.log"
perl -i -pe 's|static volatile sig_atomic_t intr_signal|static volatile int intr_signal|' crypto/ui/ui_openssl.c
perl -i -pe "s|^CC= gcc|CC= ${GCC} -arch ${ARCH} -miphoneos-version-min=${MIN_VERSION}|g" Makefile
perl -i -pe "s|^CFLAG= (.*)|CFLAG= -isysroot ${SDK} \$1|g" Makefile
make &> "/tmp/openssl-${OPENSSL_VERSION}-${ARCH}.build-log"
make install &> "/tmp/openssl-${OPENSSL_VERSION}-${ARCH}.install-log"
popd
rm -rf "openssl-${OPENSSL_VERSION}"
}
mkdir openssl
cd openssl
if [ ! -e ${OPENSSL_VERSION}.tar.gz ]; then
echo "Downloading ${OPENSSL_VERSION}.tar.gz"
curl -O http://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz
else
echo "Using ${OPENSSL_VERSION}.tar.gz"
fi
build "BSD-generic32" "armv7" "${IPHONEOS_GCC}" "${IPHONEOS_SDK}" ""
build "BSD-generic32" "armv7s" "${IPHONEOS_GCC}" "${IPHONEOS_SDK}" ""
build "BSD-generic64" "arm64" "${IPHONEOS_GCC}" "${IPHONEOS_SDK}" ""
build "BSD-generic32" "i386" "${IPHONESIMULATOR_GCC}" "${IPHONESIMULATOR_SDK}" ""
build "BSD-generic64" "x86_64" "${IPHONESIMULATOR_GCC}" "${IPHONESIMULATOR_SDK}" "-DOPENSSL_NO_ASM"
#
mkdir include
cp -r /tmp/openssl-${OPENSSL_VERSION}-i386/include/openssl include/
mkdir lib
lipo \
"/tmp/openssl-${OPENSSL_VERSION}-armv7/lib/libcrypto.a" \
"/tmp/openssl-${OPENSSL_VERSION}-armv7s/lib/libcrypto.a" \
"/tmp/openssl-${OPENSSL_VERSION}-arm64/lib/libcrypto.a" \
"/tmp/openssl-${OPENSSL_VERSION}-i386/lib/libcrypto.a" \
"/tmp/openssl-${OPENSSL_VERSION}-x86_64/lib/libcrypto.a" \
-create -output lib/libcrypto.a
lipo \
"/tmp/openssl-${OPENSSL_VERSION}-armv7/lib/libssl.a" \
"/tmp/openssl-${OPENSSL_VERSION}-armv7s/lib/libssl.a" \
"/tmp/openssl-${OPENSSL_VERSION}-arm64/lib/libssl.a" \
"/tmp/openssl-${OPENSSL_VERSION}-i386/lib/libssl.a" \
"/tmp/openssl-${OPENSSL_VERSION}-x86_64/lib/libssl.a" \
-create -output lib/libssl.a
rm -rf "/tmp/openssl-${OPENSSL_VERSION}-*"
rm -rf "/tmp/openssl-${OPENSSL_VERSION}-*.*-log"

BIN
Builds/Limelight_0_1.ipa Normal file

Binary file not shown.

BIN
Builds/Limelight_0_2.ipa Normal file

Binary file not shown.

BIN
Builds/Limelight_0_2_1.ipa Normal file

Binary file not shown.

BIN
Builds/Limelight_0_2_2.ipa Normal file

Binary file not shown.

BIN
Builds/Limelight_0_3_0.ipa Normal file

Binary file not shown.

BIN
Builds/Limelight_0_3_1.ipa Normal file

Binary file not shown.

BIN
Builds/Limelight_0_3_2.ipa Normal file

Binary file not shown.

BIN
Builds/Limelight_0_4_0.ipa Normal file

Binary file not shown.

BIN
Builds/Limelight_0_4_1.ipa Normal file

Binary file not shown.

BIN
Builds/Limelight_0_9_0.ipa Normal file

Binary file not shown.

BIN
Builds/Moonlight_0_9_2.ipa Normal file

Binary file not shown.

View file

@ -672,11 +672,3 @@ may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
App Store Distribution Exception
As additional permission under section 7, you are allowed to distribute the
software through an app store, even if that store has restrictive terms and
conditions that are incompatible with the GPL, provided that the source is
also available under the GPL with or without this permission through a channel
without those restrictive terms and conditions.

View file

@ -1,19 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina6_1" orientation="landscape" appearance="light"/>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8191" systemVersion="15A279b" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15509"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="VWy-YH-qYj">
<rect key="frame" x="0.0" y="0.0" width="896" height="414"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<point key="canvasLocation" x="33" y="187"/>
</view>
<navigationController id="vV9-32-ww6">
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="y2P-aE-Haa">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
<color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
</navigationBar>
<viewControllers>
<viewController id="l6V-ue-5Om">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="rEZ-vx-akr"/>
<viewControllerLayoutGuide type="bottom" id="gBD-cy-cth"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="6lF-fc-kpK">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
</view>
<navigationItem key="navigationItem" id="rW0-BH-s7l">
<barButtonItem key="leftBarButtonItem" enabled="NO" id="d9R-Zo-Uml">
<button key="customView" opaque="NO" contentMode="center" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="9JC-B5-BAE">
<rect key="frame" x="-23" y="-15" width="46" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<state key="normal" title="Moonlight" image="Logo">
<color key="titleColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<color key="titleShadowColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
</state>
<variation key="widthClass=regular" preservesSuperviewLayoutMargins="NO"/>
</button>
</barButtonItem>
</navigationItem>
</viewController>
</viewControllers>
</navigationController>
</objects>
<resources>
<image name="Logo" width="32" height="32"/>
</resources>
</document>

View file

@ -11,8 +11,6 @@
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) NSString *pcUuidToLoad;
@property (strong, nonatomic) void (^shortcutCompletionHandler)(BOOL);
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;

View file

@ -16,29 +16,39 @@
static NSOperationQueue* mainQueue;
#if TARGET_OS_TV
static NSString* DB_NAME = @"Moonlight_tvOS.bin";
#else
static NSString* DB_NAME = @"Limelight_iOS.sqlite";
#endif
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[UILabel appearance] setFont:[UIFont fontWithName:@"Roboto-Regular" size:[UIFont systemFontSize]]];
[[UIButton appearance].titleLabel setFont:[UIFont fontWithName:@"Roboto-Regular" size:[UIFont systemFontSize]]];
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
#if !TARGET_OS_TV
UIApplicationShortcutItem* shortcut = [launchOptions valueForKey:UIApplicationLaunchOptionsShortcutItemKey];
if (shortcut != nil) {
_pcUuidToLoad = (NSString*)[shortcut.userInfo objectForKey:@"UUID"];
}
#endif
// Generate selected segment background image
CGSize borderImageSize = CGSizeMake(1.f, 100.f);
UIGraphicsBeginImageContext(borderImageSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextFillRect(context, CGRectMake(0.f, borderImageSize.height * 0.8, borderImageSize.width, borderImageSize.height));
UIImage *selectedSegmentBG = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// Clear default border and background color
[[UISegmentedControl appearance] setBackgroundImage:[[UIImage alloc] init] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:[[UIImage alloc] init] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
// Set selected segment background image
[[UISegmentedControl appearance] setBackgroundImage:[selectedSegmentBG imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
// Change font on UISegmentedControl
[[UISegmentedControl appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
[UIColor whiteColor], NSForegroundColorAttributeName,
[UIFont fontWithName:@"Roboto-Regular" size:[UIFont systemFontSize]], NSFontAttributeName, nil] forState:UIControlStateNormal];
return YES;
}
#if !TARGET_OS_TV
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded))completionHandler {
_pcUuidToLoad = (NSString*)[shortcutItem.userInfo objectForKey:@"UUID"];
_shortcutCompletionHandler = completionHandler;
}
#endif
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
@ -47,7 +57,7 @@ static NSString* DB_NAME = @"Limelight_iOS.sqlite";
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
@ -69,22 +79,12 @@ static NSString* DB_NAME = @"Limelight_iOS.sqlite";
- (void)saveContext
{
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
[managedObjectContext performBlock:^{
if (![managedObjectContext hasChanges]) {
return;
}
NSError *error = nil;
if (![managedObjectContext save:&error]) {
Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
}
#if TARGET_OS_TV
NSData* dbData = [NSData dataWithContentsOfURL:[[[[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:DB_NAME]];
[[NSUserDefaults standardUserDefaults] setObject:dbData forKey:DB_NAME];
#endif
}];
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
}
}
}
@ -125,30 +125,19 @@ static NSString* DB_NAME = @"Limelight_iOS.sqlite";
return _persistentStoreCoordinator;
}
NSURL *storeURL = [self getStoreURL];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSString* storeType;
#if TARGET_OS_TV
// Use a binary store for tvOS since we will need exclusive access to the file
// to serialize into NSUserDefaults.
storeType = NSBinaryStoreType;
#else
storeType = NSSQLiteStoreType;
#endif
// We must ensure the persistent store is ready to opened
[self preparePersistentStore];
if (![_persistentStoreCoordinator addPersistentStoreWithType:storeType configuration:nil URL:[self getStoreURL] options:options error:&error]) {
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
// Log the error
Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
// Drop the database
[self dropDatabase];
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
// Try again
return [self persistentStoreCoordinator];
@ -165,50 +154,8 @@ static NSString* DB_NAME = @"Limelight_iOS.sqlite";
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
- (void) dropDatabase
{
// Delete the file on disk
[[NSFileManager defaultManager] removeItemAtURL:[self getStoreURL] error:nil];
#if TARGET_OS_TV
// Also delete the copy in the NSUserDefaults on tvOS
[[NSUserDefaults standardUserDefaults] removeObjectForKey:DB_NAME];
#endif
}
- (void) preparePersistentStore
{
#if TARGET_OS_TV
// On tvOS, we may need to inflate the DB from NSUserDefaults
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cacheDirectory = [paths objectAtIndex:0];
NSString *dbPath = [cacheDirectory stringByAppendingPathComponent:DB_NAME];
// Always prefer the on disk version
if (![[NSFileManager defaultManager] fileExistsAtPath:dbPath]) {
// If that is unavailable, inflate it from NSUserDefaults
NSData* data = [[NSUserDefaults standardUserDefaults] dataForKey:DB_NAME];
if (data != nil) {
Log(LOG_I, @"Inflating database from NSUserDefaults");
[data writeToFile:dbPath atomically:YES];
}
else {
Log(LOG_I, @"No database on disk or in NSUserDefaults");
}
}
else {
Log(LOG_I, @"Using cached database");
}
#endif
}
- (NSURL*) getStoreURL {
#if TARGET_OS_TV
// We use the cache folder to store our database on tvOS
return [[[[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:DB_NAME];
#else
return [[self applicationDocumentsDirectory] URLByAppendingPathComponent:DB_NAME];
#endif
return [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Limelight_iOS.sqlite"];
}
@end

View file

@ -6,14 +6,16 @@
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface CryptoManager : NSObject
+ (void) generateKeyPairUsingSSL;
+ (void) generateKeyPairUsingSSl;
+ (NSData*) readCertFromFile;
+ (NSData*) readKeyFromFile;
+ (NSData*) readP12FromFile;
+ (NSData*) getSignatureFromCert:(NSData*)cert;
+ (NSData*) pemToDer:(NSData*)pemCertBytes;
+ (NSData*) nullTerminateString:(NSData*)data;
- (NSData*) createAESKeyFromSaltSHA1:(NSData*)saltedPIN;
- (NSData*) createAESKeyFromSaltSHA256:(NSData*)saltedPIN;

View file

@ -9,6 +9,7 @@
#import "CryptoManager.h"
#import "mkcert.h"
#include <openssl/aes.h>
#include <openssl/sha.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
@ -44,72 +45,59 @@ static NSData* p12 = nil;
}
- (NSData*) aesEncrypt:(NSData*)data withKey:(NSData*)key {
EVP_CIPHER_CTX* cipher;
int ciphertextLen;
cipher = EVP_CIPHER_CTX_new();
EVP_EncryptInit(cipher, EVP_aes_128_ecb(), [key bytes], NULL);
EVP_CIPHER_CTX_set_padding(cipher, 0);
NSMutableData* ciphertext = [NSMutableData dataWithLength:[data length]];
EVP_EncryptUpdate(cipher,
[ciphertext mutableBytes],
&ciphertextLen,
[data bytes],
(int)[data length]);
assert(ciphertextLen == [ciphertext length]);
EVP_CIPHER_CTX_free(cipher);
AES_KEY aesKey;
AES_set_encrypt_key([key bytes], 128, &aesKey);
int size = [self getEncryptSize:data];
unsigned char* buffer = malloc(size);
unsigned char* blockRoundedBuffer = calloc(1, size);
memcpy(blockRoundedBuffer, [data bytes], [data length]);
return ciphertext;
// AES_encrypt only encrypts the first 16 bytes so iterate the entire buffer
int blockOffset = 0;
while (blockOffset < size) {
AES_encrypt(blockRoundedBuffer + blockOffset, buffer + blockOffset, &aesKey);
blockOffset += 16;
}
NSData* encryptedData = [NSData dataWithBytes:buffer length:size];
free(buffer);
free(blockRoundedBuffer);
return encryptedData;
}
- (NSData*) aesDecrypt:(NSData*)data withKey:(NSData*)key {
EVP_CIPHER_CTX* cipher;
int plaintextLen;
cipher = EVP_CIPHER_CTX_new();
EVP_DecryptInit(cipher, EVP_aes_128_ecb(), [key bytes], NULL);
EVP_CIPHER_CTX_set_padding(cipher, 0);
NSMutableData* plaintext = [NSMutableData dataWithLength:[data length]];
EVP_DecryptUpdate(cipher,
[plaintext mutableBytes],
&plaintextLen,
[data bytes],
(int)[data length]);
assert(plaintextLen == [plaintext length]);
EVP_CIPHER_CTX_free(cipher);
AES_KEY aesKey;
AES_set_decrypt_key([key bytes], 128, &aesKey);
unsigned char* buffer = malloc([data length]);
return plaintext;
// AES_decrypt only decrypts the first 16 bytes so iterate the entire buffer
int blockOffset = 0;
while (blockOffset < [data length]) {
AES_decrypt([data bytes] + blockOffset, buffer + blockOffset, &aesKey);
blockOffset += 16;
}
NSData* decryptedData = [NSData dataWithBytes:buffer length:[data length]];
free(buffer);
return decryptedData;
}
+ (NSData*) pemToDer:(NSData*)pemCertBytes {
X509* x509;
BIO* bio = BIO_new_mem_buf([pemCertBytes bytes], (int)[pemCertBytes length]);
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
BIO_free(bio);
bio = BIO_new(BIO_s_mem());
i2d_X509_bio(bio, x509);
X509_free(x509);
- (int) getEncryptSize:(NSData*)data {
// the size is the length of the data ceiling to the nearest 16 bytes
return (((int)[data length] + 15) / 16) * 16;
}
BUF_MEM* mem;
BIO_get_mem_ptr(bio, &mem);
NSData* ret = [[NSData alloc] initWithBytes:mem->data length:mem->length];
BIO_free(bio);
return ret;
+ (NSData*) nullTerminateString:(NSData*)data {
NSMutableData* mutData = [NSMutableData dataWithData:data];
[mutData appendBytes:"" length:1];
return mutData;
}
- (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert {
const char* buffer = [[CryptoManager nullTerminateString:cert] bytes];
X509* x509;
BIO* bio = BIO_new_mem_buf([cert bytes], (int)[cert length]);
BIO* bio = BIO_new(BIO_s_mem());
BIO_puts(bio, buffer);
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
BIO_free(bio);
@ -134,7 +122,9 @@ static NSData* p12 = nil;
}
- (NSData *)signData:(NSData *)data withKey:(NSData *)key {
BIO* bio = BIO_new_mem_buf([key bytes], (int)[key length]);
const char* buffer = [[CryptoManager nullTerminateString:key] bytes];
BIO* bio = BIO_new(BIO_s_mem());
BIO_puts(bio, buffer);
EVP_PKEY* pkey;
pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
@ -169,137 +159,82 @@ static NSData* p12 = nil;
return signedData;
}
+ (NSData*) readCryptoObject:(NSString*)item {
#if TARGET_OS_TV
return [[NSUserDefaults standardUserDefaults] dataForKey:item];
#else
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *file = [documentsDirectory stringByAppendingPathComponent:item];
return [NSData dataWithContentsOfFile:file];
#endif
}
+ (void) writeCryptoObject:(NSString*)item data:(NSData*)data {
#if TARGET_OS_TV
[[NSUserDefaults standardUserDefaults] setObject:data forKey:item];
#else
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *file = [documentsDirectory stringByAppendingPathComponent:item];
[data writeToFile:file atomically:NO];
#endif
}
// TODO: these three methods are almost identical, fix the copy-pasta
+ (NSData*) readCertFromFile {
if (cert == nil) {
cert = [CryptoManager readCryptoObject:@"client.crt"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *certFile = [documentsDirectory stringByAppendingPathComponent:@"client.crt"];
cert = [NSData dataWithContentsOfFile:certFile];
}
return cert;
}
+ (NSData*) readP12FromFile {
if (p12 == nil) {
p12 = [CryptoManager readCryptoObject:@"client.p12"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *p12File = [documentsDirectory stringByAppendingPathComponent:@"client.p12"];
p12 = [NSData dataWithContentsOfFile:p12File];
}
return p12;
}
+ (NSData*) readKeyFromFile {
if (key == nil) {
key = [CryptoManager readCryptoObject:@"client.key"];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *keyFile = [documentsDirectory stringByAppendingPathComponent:@"client.key"];
key = [NSData dataWithContentsOfFile:keyFile];
}
return key;
}
+ (bool) keyPairExists {
bool keyFileExists = [CryptoManager readCryptoObject:@"client.key"] != nil;
bool p12FileExists = [CryptoManager readCryptoObject:@"client.p12"] != nil;
bool certFileExists = [CryptoManager readCryptoObject:@"client.crt"] != nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *keyFile = [documentsDirectory stringByAppendingPathComponent:@"client.key"];
NSString *p12File = [documentsDirectory stringByAppendingPathComponent:@"client.p12"];
NSString *certFile = [documentsDirectory stringByAppendingPathComponent:@"client.crt"];
bool keyFileExists = [[NSFileManager defaultManager] fileExistsAtPath:keyFile];
bool p12FileExists = [[NSFileManager defaultManager] fileExistsAtPath:p12File];
bool certFileExists = [[NSFileManager defaultManager] fileExistsAtPath:certFile];
return keyFileExists && p12FileExists && certFileExists;
}
+ (NSData *)getSignatureFromCert:(NSData *)cert {
BIO* bio = BIO_new_mem_buf([cert bytes], (int)[cert length]);
X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
BIO_free(bio);
const char* buffer = [[CryptoManager nullTerminateString:cert] bytes];
X509* x509;
BIO* bio = BIO_new(BIO_s_mem());
BIO_puts(bio, buffer);
x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
if (!x509) {
Log(LOG_E, @"Unable to parse certificate in memory!");
return NULL;
}
#if (OPENSSL_VERSION_NUMBER < 0x10002000L)
ASN1_BIT_STRING *asnSignature = x509->signature;
#elif (OPENSSL_VERSION_NUMBER < 0x10100000L)
ASN1_BIT_STRING *asnSignature;
X509_get0_signature(&asnSignature, NULL, x509);
#else
const ASN1_BIT_STRING *asnSignature;
X509_get0_signature(&asnSignature, NULL, x509);
#endif
NSData* sig = [NSData dataWithBytes:asnSignature->data length:asnSignature->length];
X509_free(x509);
return sig;
return [NSData dataWithBytes:x509->signature->data length:x509->signature->length];
}
+ (NSData*)getKeyFromCertKeyPair:(CertKeyPair*)certKeyPair {
BIO* bio = BIO_new(BIO_s_mem());
PEM_write_bio_PrivateKey_traditional(bio, certKeyPair->pkey, NULL, NULL, 0, NULL, NULL);
BUF_MEM* mem;
BIO_get_mem_ptr(bio, &mem);
NSData* data = [NSData dataWithBytes:mem->data length:mem->length];
BIO_free(bio);
return data;
}
+ (NSData*)getP12FromCertKeyPair:(CertKeyPair*)certKeyPair {
BIO* bio = BIO_new(BIO_s_mem());
i2d_PKCS12_bio(bio, certKeyPair->p12);
BUF_MEM* mem;
BIO_get_mem_ptr(bio, &mem);
NSData* data = [NSData dataWithBytes:mem->data length:mem->length];
BIO_free(bio);
return data;
}
+ (NSData*)getCertFromCertKeyPair:(CertKeyPair*)certKeyPair {
BIO* bio = BIO_new(BIO_s_mem());
PEM_write_bio_X509(bio, certKeyPair->x509);
BUF_MEM* mem;
BIO_get_mem_ptr(bio, &mem);
NSData* data = [NSData dataWithBytes:mem->data length:mem->length];
BIO_free(bio);
return data;
}
+ (void) generateKeyPairUsingSSL {
+ (void) generateKeyPairUsingSSl {
static dispatch_once_t pred;
dispatch_once(&pred, ^{
if (![CryptoManager keyPairExists]) {
Log(LOG_I, @"Generating Certificate... ");
CertKeyPair certKeyPair = generateCertKeyPair();
NSData* certData = [CryptoManager getCertFromCertKeyPair:&certKeyPair];
NSData* p12Data = [CryptoManager getP12FromCertKeyPair:&certKeyPair];
NSData* keyData = [CryptoManager getKeyFromCertKeyPair:&certKeyPair];
NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documentsDirectory = [paths objectAtIndex:0];
NSString* certFile = [documentsDirectory stringByAppendingPathComponent:@"client.crt"];
NSString* keyPairFile = [documentsDirectory stringByAppendingPathComponent:@"client.key"];
NSString* p12File = [documentsDirectory stringByAppendingPathComponent:@"client.p12"];
//Log(LOG_D, @"Writing cert and key to: \n%@\n%@", certFile, keyPairFile);
saveCertKeyPair([certFile UTF8String], [p12File UTF8String], [keyPairFile UTF8String], certKeyPair);
freeCertKeyPair(certKeyPair);
[CryptoManager writeCryptoObject:@"client.crt" data:certData];
[CryptoManager writeCryptoObject:@"client.p12" data:p12Data];
[CryptoManager writeCryptoObject:@"client.key" data:keyData];
Log(LOG_I, @"Certificate created");
}
});

View file

@ -6,6 +6,8 @@
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface IdManager : NSObject
+ (NSString*) getUniqueId;

View file

@ -4,88 +4,54 @@
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <OpenSSL/provider.h>
#include <OpenSSL/rsa.h>
#include <openssl/x509.h>
#include <OpenSSL/rand.h>
#include <openssl/conf.h>
#include <openssl/pkcs12.h>
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif
static const int NUM_BITS = 2048;
static const int SERIAL = 0;
static const int NUM_YEARS = 20;
static const int NUM_YEARS = 10;
void mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
X509* cert = X509_new();
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years);
int add_ext(X509 *cert, int nid, char *value);
EVP_PKEY_keygen_init(ctx);
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits);
// pk must be initialized on input
EVP_PKEY* pk = NULL;
EVP_PKEY_keygen(ctx, &pk);
EVP_PKEY_CTX_free(ctx);
X509_set_version(cert, 2);
ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
X509_gmtime_adj(X509_get_notBefore(cert), 0);
X509_gmtime_adj(X509_get_notAfter(cert), 60 * 60 * 24 * 365 * years);
#else
ASN1_TIME* before = ASN1_STRING_dup(X509_get0_notBefore(cert));
ASN1_TIME* after = ASN1_STRING_dup(X509_get0_notAfter(cert));
X509_gmtime_adj(before, 0);
X509_gmtime_adj(after, 60 * 60 * 24 * 365 * years);
X509_set1_notBefore(cert, before);
X509_set1_notAfter(cert, after);
ASN1_STRING_free(before);
ASN1_STRING_free(after);
#endif
X509_set_pubkey(cert, pk);
X509_NAME* name = X509_get_subject_name(cert);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
(const unsigned char*)"NVIDIA GameStream Client",
-1, -1, 0);
X509_set_issuer_name(cert, name);
X509_sign(cert, pk, EVP_sha256());
*x509p = cert;
*pkeyp = pk;
}
struct CertKeyPair generateCertKeyPair(void) {
struct CertKeyPair generateCertKeyPair() {
BIO *bio_err;
X509 *x509 = NULL;
EVP_PKEY *pkey = NULL;
PKCS12 *p12 = NULL;
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
SSLeay_add_all_algorithms();
ERR_load_crypto_strings();
mkcert(&x509, &pkey, NUM_BITS, SERIAL, NUM_YEARS);
char* pass = "limelight";
p12 = PKCS12_create(pass,
"GameStream",
pkey,
x509,
NULL,
NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
-1, // disable certificate encryption
2048,
-1, // disable the automatic MAC
0);
// MAC it ourselves with SHA1 since iOS refuses to load anything else.
PKCS12_set_mac(p12, pass, -1, NULL, 0, 1, EVP_sha1());
p12 = PKCS12_create("limelight", "GameStream", pkey, x509, NULL, 0, 0, 0, 0, 0);
if (p12 == NULL) {
printf("Error generating a valid PKCS12 certificate.\n");
}
// Debug Print statements
//RSA_print_fp(stdout, pkey->pkey.rsa, 0);
//X509_print_fp(stdout, x509);
//PEM_write_PUBKEY(stdout, pkey);
//PEM_write_PrivateKey(stdout, pkey, NULL, NULL, 0, NULL, NULL);
//PEM_write_X509(stdout, x509);
#ifndef OPENSSL_NO_ENGINE
ENGINE_cleanup();
#endif
CRYPTO_cleanup_all_ex_data();
CRYPTO_mem_leaks(bio_err);
BIO_free(bio_err);
return (CertKeyPair){x509, pkey, p12};
}
@ -95,3 +61,107 @@ void freeCertKeyPair(struct CertKeyPair certKeyPair) {
EVP_PKEY_free(certKeyPair.pkey);
PKCS12_free(certKeyPair.p12);
}
void saveCertKeyPair(const char* certFile, const char* p12File, const char* keyPairFile, CertKeyPair certKeyPair) {
FILE* certFilePtr = fopen(certFile, "w");
FILE* keyPairFilePtr = fopen(keyPairFile, "w");
FILE* p12FilePtr = fopen(p12File, "wb");
//TODO: error check
PEM_write_PrivateKey(keyPairFilePtr, certKeyPair.pkey, NULL, NULL, 0, NULL, NULL);
PEM_write_X509(certFilePtr, certKeyPair.x509);
i2d_PKCS12_fp(p12FilePtr, certKeyPair.p12);
fclose(p12FilePtr);
fclose(certFilePtr);
fclose(keyPairFilePtr);
}
int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
X509 *x;
EVP_PKEY *pk;
RSA *rsa;
X509_NAME *name = NULL;
if (*pkeyp == NULL) {
if ((pk=EVP_PKEY_new()) == NULL) {
return(0);
}
} else {
pk = *pkeyp;
}
if (*x509p == NULL) {
if ((x = X509_new()) == NULL) {
goto err;
}
} else {
x = *x509p;
}
rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
goto err;
}
X509_set_version(x, 2);
ASN1_INTEGER_set(X509_get_serialNumber(x), serial);
X509_gmtime_adj(X509_get_notBefore(x), 0);
X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*365*years);
X509_set_pubkey(x, pk);
name = X509_get_subject_name(x);
/* This function creates and adds the entry, working out the
* correct string type and performing checks on its length.
*/
X509_NAME_add_entry_by_txt(name,"CN", MBSTRING_ASC, (unsigned char*)"NVIDIA GameStream Client", -1, -1, 0);
/* Its self signed so set the issuer name to be the same as the
* subject.
*/
X509_set_issuer_name(x, name);
/* Add various extensions: standard extensions */
add_ext(x, NID_basic_constraints, "critical,CA:TRUE");
add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign");
add_ext(x, NID_subject_key_identifier, "hash");
if (!X509_sign(x, pk, EVP_sha1())) {
goto err;
}
*x509p = x;
*pkeyp = pk;
return(1);
err:
return(0);
}
/* Add extension using V3 code: we can set the config file as NULL
* because we wont reference any other sections.
*/
int add_ext(X509 *cert, int nid, char *value)
{
X509_EXTENSION *ex;
X509V3_CTX ctx;
/* This sets the 'context' of the extensions. */
/* No configuration database */
X509V3_set_ctx_nodb(&ctx);
/* Issuer and subject certs: both the target since it is self signed,
* no request and no CRL
*/
X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
if (!ex) {
return 0;
}
X509_add_ext(cert, ex, -1);
X509_EXTENSION_free(ex);
return 1;
}

View file

@ -18,7 +18,8 @@ typedef struct CertKeyPair {
PKCS12 *p12;
} CertKeyPair;
struct CertKeyPair generateCertKeyPair(void);
struct CertKeyPair generateCertKeyPair();
void freeCertKeyPair(CertKeyPair);
void saveCertKeyPair(const char* certFile, const char* p12File, const char* keyPairFile, CertKeyPair certKeyPair);
#endif

View file

@ -0,0 +1,25 @@
//
// App+CoreDataProperties.h
// Moonlight
//
// Created by Diego Waxemberg on 7/10/15.
// Copyright © 2015 Limelight Stream. All rights reserved.
//
// Delete this file and regenerate it using "Create NSManagedObject Subclass…"
// to keep your implementation up to date with your model.
//
#import "App.h"
NS_ASSUME_NONNULL_BEGIN
@interface App (CoreDataProperties)
@property (nullable, nonatomic, retain) NSString *id;
@property (nullable, nonatomic, retain) NSData *image;
@property (nullable, nonatomic, retain) NSString *name;
@property (nullable, nonatomic, retain) Host *host;
@end
NS_ASSUME_NONNULL_END

18
Limelight/Database/App.h Normal file
View file

@ -0,0 +1,18 @@
//
// App.h
// Moonlight
//
// Created by Diego Waxemberg on 7/10/15.
// Copyright © 2015 Limelight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@class Host;
@interface App : NSManagedObject
@end
#import "App+CoreDataProperties.h"

13
Limelight/Database/App.m Normal file
View file

@ -0,0 +1,13 @@
//
// App.m
// Moonlight
//
// Created by Diego Waxemberg on 7/10/15.
// Copyright © 2015 Limelight Stream. All rights reserved.
//
#import "App.h"
@implementation App
@end

View file

@ -6,6 +6,7 @@
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "AppDelegate.h"
#import "TemporaryHost.h"
#import "TemporaryApp.h"
@ -13,26 +14,12 @@
@interface DataManager : NSObject
- (void) saveSettingsWithBitrate:(NSInteger)bitrate
framerate:(NSInteger)framerate
height:(NSInteger)height
width:(NSInteger)width
audioConfig:(NSInteger)audioConfig
onscreenControls:(NSInteger)onscreenControls
optimizeGames:(BOOL)optimizeGames
multiController:(BOOL)multiController
swapABXYButtons:(BOOL)swapABXYButtons
audioOnPC:(BOOL)audioOnPC
preferredCodec:(uint32_t)preferredCodec
useFramePacing:(BOOL)useFramePacing
enableHdr:(BOOL)enableHdr
btMouseSupport:(BOOL)btMouseSupport
absoluteTouchMode:(BOOL)absoluteTouchMode
statsOverlay:(BOOL)statsOverlay;
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls;
- (NSArray*) getHosts;
- (void) updateHost:(TemporaryHost*)host;
- (void) updateAppsForExistingHost:(TemporaryHost *)host;
- (void) updateIconForExistingApp:(TemporaryApp*)app;
- (void) removeHost:(TemporaryHost*)host;
- (void) removeApp:(TemporaryApp*)app;

View file

@ -9,6 +9,7 @@
#import "DataManager.h"
#import "TemporaryApp.h"
#import "TemporarySettings.h"
#import "Settings.h"
@implementation DataManager {
NSManagedObjectContext *_managedObjectContext;
@ -18,19 +19,9 @@
- (id) init {
self = [super init];
// HACK: Avoid calling [UIApplication delegate] off the UI thread to keep
// Main Thread Checker happy.
if ([NSThread isMainThread]) {
_appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
else {
dispatch_sync(dispatch_get_main_queue(), ^{
self->_appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
});
}
_appDelegate = [[UIApplication sharedApplication] delegate];
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setParentContext:[_appDelegate managedObjectContext]];
[_managedObjectContext setPersistentStoreCoordinator:_appDelegate.persistentStoreCoordinator];
return self;
}
@ -52,41 +43,16 @@
return uid;
}
- (void) saveSettingsWithBitrate:(NSInteger)bitrate
framerate:(NSInteger)framerate
height:(NSInteger)height
width:(NSInteger)width
audioConfig:(NSInteger)audioConfig
onscreenControls:(NSInteger)onscreenControls
optimizeGames:(BOOL)optimizeGames
multiController:(BOOL)multiController
swapABXYButtons:(BOOL)swapABXYButtons
audioOnPC:(BOOL)audioOnPC
preferredCodec:(uint32_t)preferredCodec
useFramePacing:(BOOL)useFramePacing
enableHdr:(BOOL)enableHdr
btMouseSupport:(BOOL)btMouseSupport
absoluteTouchMode:(BOOL)absoluteTouchMode
statsOverlay:(BOOL)statsOverlay {
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls {
[_managedObjectContext performBlockAndWait:^{
Settings* settingsToSave = [self retrieveSettings];
settingsToSave.framerate = [NSNumber numberWithInteger:framerate];
// Bitrate is persisted in kbps
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate];
settingsToSave.height = [NSNumber numberWithInteger:height];
settingsToSave.width = [NSNumber numberWithInteger:width];
settingsToSave.audioConfig = [NSNumber numberWithInteger:audioConfig];
settingsToSave.onscreenControls = [NSNumber numberWithInteger:onscreenControls];
settingsToSave.optimizeGames = optimizeGames;
settingsToSave.multiController = multiController;
settingsToSave.swapABXYButtons = swapABXYButtons;
settingsToSave.playAudioOnPC = audioOnPC;
settingsToSave.preferredCodec = preferredCodec;
settingsToSave.useFramePacing = useFramePacing;
settingsToSave.enableHdr = enableHdr;
settingsToSave.btMouseSupport = btMouseSupport;
settingsToSave.absoluteTouchMode = absoluteTouchMode;
settingsToSave.statsOverlay = statsOverlay;
[self saveData];
}];
@ -97,8 +63,8 @@
// Add a new persistent managed object if one doesn't exist
Host* parent = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
if (parent == nil) {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:self->_managedObjectContext];
parent = [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:self->_managedObjectContext];
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:_managedObjectContext];
parent = [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
}
// Push changes from the temp host to the persistent one
@ -122,8 +88,8 @@
// Add a new persistent managed object if one doesn't exist
App* parentApp = [self getAppForTemporaryApp:app withAppRecords:appRecords];
if (parentApp == nil) {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:self->_managedObjectContext];
parentApp = [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:self->_managedObjectContext];
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:_managedObjectContext];
parentApp = [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:_managedObjectContext];
}
[app propagateChangesToParent:parentApp withHost:parent];
@ -137,6 +103,20 @@
}];
}
- (void) updateIconForExistingApp:(TemporaryApp*)app {
[_managedObjectContext performBlockAndWait:^{
App* parentApp = [self getAppForTemporaryApp:app withAppRecords:[self fetchRecords:@"App"]];
if (parentApp == nil) {
// The app must exist to be updated
return;
}
parentApp.image = app.image;
[self saveData];
}];
}
- (TemporarySettings*) getSettings {
__block TemporarySettings *tempSettings;
@ -165,7 +145,7 @@
[_managedObjectContext performBlockAndWait:^{
App* managedApp = [self getAppForTemporaryApp:app withAppRecords:[self fetchRecords:@"App"]];
if (managedApp != nil) {
[self->_managedObjectContext deleteObject:managedApp];
[_managedObjectContext deleteObject:managedApp];
[self saveData];
}
}];
@ -175,7 +155,7 @@
[_managedObjectContext performBlockAndWait:^{
Host* managedHost = [self getHostForTemporaryHost:host withHostRecords:[self fetchRecords:@"Host"]];
if (managedHost != nil) {
[self->_managedObjectContext deleteObject:managedHost];
[_managedObjectContext deleteObject:managedHost];
[self saveData];
}
}];
@ -183,7 +163,7 @@
- (void) saveData {
NSError* error;
if ([_managedObjectContext hasChanges] && ![_managedObjectContext save:&error]) {
if (![_managedObjectContext save:&error]) {
Log(LOG_E, @"Unable to save hosts to database: %@", error);
}
@ -219,7 +199,7 @@
- (App*) getAppForTemporaryApp:(TemporaryApp*)tempApp withAppRecords:(NSArray*)apps {
for (App* app in apps) {
if ([app.id isEqualToString:tempApp.id] &&
[app.host.uuid isEqualToString:tempApp.host.uuid]) {
[app.host.uuid isEqualToString:app.host.uuid]) {
return app;
}
}

View file

@ -0,0 +1,38 @@
//
// Host+CoreDataProperties.h
// Moonlight
//
// Created by Diego Waxemberg on 7/10/15.
// Copyright © 2015 Limelight Stream. All rights reserved.
//
// Delete this file and regenerate it using "Create NSManagedObject Subclass…"
// to keep your implementation up to date with your model.
//
#import "Host.h"
NS_ASSUME_NONNULL_BEGIN
@interface Host (CoreDataProperties)
@property (nullable, nonatomic, retain) NSString *address;
@property (nullable, nonatomic, retain) NSString *externalAddress;
@property (nullable, nonatomic, retain) NSString *localAddress;
@property (nullable, nonatomic, retain) NSString *mac;
@property (nullable, nonatomic, retain) NSString *name;
@property (nullable, nonatomic, retain) NSNumber *pairState;
@property (nullable, nonatomic, retain) NSString *uuid;
@property (nullable, nonatomic, retain) NSSet *appList;
@end
@interface Host (CoreDataGeneratedAccessors)
- (void)addAppListObject:(NSManagedObject *)value;
- (void)removeAppListObject:(NSManagedObject *)value;
- (void)addAppList:(NSSet *)values;
- (void)removeAppList:(NSSet *)values;
@end
NS_ASSUME_NONNULL_END

17
Limelight/Database/Host.h Normal file
View file

@ -0,0 +1,17 @@
//
// Host.h
// Moonlight
//
// Created by Diego Waxemberg on 7/10/15.
// Copyright © 2015 Limelight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "Utils.h"
@interface Host : NSManagedObject
@end
#import "Host+CoreDataProperties.h"

13
Limelight/Database/Host.m Normal file
View file

@ -0,0 +1,13 @@
//
// Host.m
// Moonlight
//
// Created by Diego Waxemberg on 7/10/15.
// Copyright © 2015 Limelight Stream. All rights reserved.
//
#import "Host.h"
@implementation Host
@end

View file

@ -0,0 +1,22 @@
//
// Settings.h
// Moonlight
//
// Created by Diego Waxemberg on 10/28/14.
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface Settings : NSManagedObject
@property (nonatomic, retain) NSNumber * bitrate;
@property (nonatomic, retain) NSNumber * framerate;
@property (nonatomic, retain) NSNumber * height;
@property (nonatomic, retain) NSNumber * width;
@property (nonatomic, retain) NSNumber * onscreenControls;
@property (nonatomic, retain) NSString * uniqueId;
@end

View file

@ -0,0 +1,21 @@
//
// Settings.m
// Moonlight
//
// Created by Diego Waxemberg on 10/28/14.
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
//
#import "Settings.h"
@implementation Settings
@dynamic bitrate;
@dynamic framerate;
@dynamic height;
@dynamic width;
@dynamic onscreenControls;
@dynamic uniqueId;
@end

View file

@ -6,16 +6,15 @@
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "TemporaryHost.h"
#import "App+CoreDataClass.h"
#import "App.h"
@interface TemporaryApp : NSObject
@property (nullable, nonatomic, retain) NSString *id;
@property (nullable, nonatomic, retain) NSData *image;
@property (nullable, nonatomic, retain) NSString *name;
@property (nullable, nonatomic, retain) NSString *installPath;
@property (nonatomic) BOOL hdrSupported;
@property (nonatomic) BOOL hidden;
@property (nullable, nonatomic, retain) TemporaryHost *host;
NS_ASSUME_NONNULL_BEGIN

View file

@ -7,6 +7,7 @@
//
#import "TemporaryApp.h"
#import "App.h"
@implementation TemporaryApp
@ -14,9 +15,8 @@
self = [self init];
self.id = app.id;
self.image = app.image;
self.name = app.name;
self.hdrSupported = app.hdrSupported;
self.hidden = app.hidden;
self.host = tempHost;
return self;
@ -25,8 +25,6 @@
- (void) propagateChangesToParent:(App*)parent withHost:(Host*)host {
parent.id = self.id;
parent.name = self.name;
parent.hdrSupported = self.hdrSupported;
parent.hidden = self.hidden;
parent.host = host;
}
@ -43,7 +41,7 @@
return YES;
}
if (![object isKindOfClass:[self class]]) {
if (![object isKindOfClass:[App class]]) {
return NO;
}

View file

@ -6,31 +6,26 @@
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Utils.h"
#import "Host+CoreDataClass.h"
#import "Host.h"
@interface TemporaryHost : NSObject
@property (atomic) State state;
@property (atomic) PairState pairState;
@property (atomic, nullable, retain) NSString * activeAddress;
@property (atomic, nullable, retain) NSString * currentGame;
@property (atomic) unsigned short httpsPort;
@property (atomic) BOOL isNvidiaServerSoftware;
@property (atomic, nullable, retain) NSData *serverCert;
@property (atomic, nullable, retain) NSString *address;
@property (atomic, nullable, retain) NSString *externalAddress;
@property (atomic, nullable, retain) NSString *localAddress;
@property (atomic, nullable, retain) NSString *ipv6Address;
@property (atomic, nullable, retain) NSString *mac;
@property (atomic) int serverCodecModeSupport;
@property (nonatomic) BOOL online;
@property (nonatomic) PairState pairState;
@property (nonatomic, nullable) NSString * activeAddress;
@property (nonatomic, nullable) NSString * currentGame;
NS_ASSUME_NONNULL_BEGIN
@property (atomic, retain) NSString *name;
@property (atomic, retain) NSString *uuid;
@property (atomic, retain) NSSet *appList;
@property (nonatomic, retain) NSString *address;
@property (nonatomic, retain) NSString *externalAddress;
@property (nonatomic, retain) NSString *localAddress;
@property (nonatomic, retain) NSString *mac;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *uuid;
@property (nonatomic, retain) NSMutableSet *appList;
- (id) initFromHost:(Host*)host;

View file

@ -8,7 +8,9 @@
#import "DataManager.h"
#import "TemporaryHost.h"
#import "Host.h"
#import "TemporaryApp.h"
#import "App.h"
@implementation TemporaryHost
@ -16,7 +18,6 @@
self = [super init];
self.appList = [[NSMutableSet alloc] init];
self.currentGame = @"0";
self.state = StateUnknown;
return self;
}
@ -27,20 +28,10 @@
self.address = host.address;
self.externalAddress = host.externalAddress;
self.localAddress = host.localAddress;
self.ipv6Address = host.ipv6Address;
self.mac = host.mac;
self.name = host.name;
self.uuid = host.uuid;
self.serverCodecModeSupport = host.serverCodecModeSupport;
self.serverCert = host.serverCert;
// Older clients stored a non-URL-escaped IPv6 string. Try to detect that and fix it up.
if (![self.ipv6Address containsString:@"["]) {
self.ipv6Address = [Utils addressAndPortToAddressPortString:self.ipv6Address port:47989];
}
// Ensure we don't use a stale cached pair state if we haven't pinned the cert yet
self.pairState = host.serverCert ? [host.pairState intValue] : PairStateUnpaired;
self.pairState = [host.pairState intValue];
NSMutableSet *appList = [[NSMutableSet alloc] init];
@ -55,30 +46,12 @@
}
- (void) propagateChangesToParent:(Host*)parentHost {
// Avoid overwriting existing data with nil if
// we don't have everything populated in the temporary
// host.
if (self.address != nil) {
parentHost.address = self.address;
}
if (self.externalAddress != nil) {
parentHost.externalAddress = self.externalAddress;
}
if (self.localAddress != nil) {
parentHost.localAddress = self.localAddress;
}
if (self.ipv6Address != nil) {
parentHost.ipv6Address = self.ipv6Address;
}
if (self.mac != nil) {
parentHost.mac = self.mac;
}
if (self.serverCert != nil) {
parentHost.serverCert = self.serverCert;
}
parentHost.address = self.address;
parentHost.externalAddress = self.externalAddress;
parentHost.localAddress = self.localAddress;
parentHost.mac = self.mac;
parentHost.name = self.name;
parentHost.uuid = self.uuid;
parentHost.serverCodecModeSupport = self.serverCodecModeSupport;
parentHost.pairState = [NSNumber numberWithInt:self.pairState];
}
@ -95,7 +68,7 @@
return YES;
}
if (![object isKindOfClass:[self class]]) {
if (![object isKindOfClass:[Host class]]) {
return NO;
}

View file

@ -6,7 +6,8 @@
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "Settings+CoreDataClass.h"
#import <Foundation/Foundation.h>
#import "Settings.h"
@interface TemporarySettings : NSObject
@ -16,24 +17,8 @@
@property (nonatomic, retain) NSNumber * framerate;
@property (nonatomic, retain) NSNumber * height;
@property (nonatomic, retain) NSNumber * width;
@property (nonatomic, retain) NSNumber * audioConfig;
@property (nonatomic, retain) NSNumber * onscreenControls;
@property (nonatomic, retain) NSString * uniqueId;
@property (nonatomic) enum {
CODEC_PREF_AUTO,
CODEC_PREF_H264,
CODEC_PREF_HEVC,
CODEC_PREF_AV1,
} preferredCodec;
@property (nonatomic) BOOL useFramePacing;
@property (nonatomic) BOOL multiController;
@property (nonatomic) BOOL swapABXYButtons;
@property (nonatomic) BOOL playAudioOnPC;
@property (nonatomic) BOOL optimizeGames;
@property (nonatomic) BOOL enableHdr;
@property (nonatomic) BOOL btMouseSupport;
@property (nonatomic) BOOL absoluteTouchMode;
@property (nonatomic) BOOL statsOverlay;
- (id) initFromSettings:(Settings*)settings;

View file

@ -7,7 +7,6 @@
//
#import "TemporarySettings.h"
#import "OnScreenControls.h"
@implementation TemporarySettings
@ -16,76 +15,11 @@
self.parent = settings;
#if TARGET_OS_TV
// Apply default values from our Root.plist
NSString* settingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
NSDictionary* settingsData = [NSDictionary dictionaryWithContentsOfFile:[settingsBundle stringByAppendingPathComponent:@"Root.plist"]];
NSArray* preferences = [settingsData objectForKey:@"PreferenceSpecifiers"];
NSMutableDictionary* defaultsToRegister = [[NSMutableDictionary alloc] initWithCapacity:[preferences count]];
for (NSDictionary* prefSpecification in preferences) {
NSString* key = [prefSpecification objectForKey:@"Key"];
if (key != nil) {
[defaultsToRegister setObject:[prefSpecification objectForKey:@"DefaultValue"] forKey:key];
}
}
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsToRegister];
self.bitrate = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"bitrate"]];
assert([self.bitrate intValue] != 0);
self.framerate = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"framerate"]];
assert([self.framerate intValue] != 0);
self.audioConfig = [NSNumber numberWithInteger:[[NSUserDefaults standardUserDefaults] integerForKey:@"audioConfig"]];
assert([self.audioConfig intValue] != 0);
self.preferredCodec = (typeof(self.preferredCodec))[[NSUserDefaults standardUserDefaults] integerForKey:@"preferredCodec"];
self.useFramePacing = [[NSUserDefaults standardUserDefaults] integerForKey:@"useFramePacing"] != 0;
self.playAudioOnPC = [[NSUserDefaults standardUserDefaults] boolForKey:@"audioOnPC"];
self.enableHdr = [[NSUserDefaults standardUserDefaults] boolForKey:@"enableHdr"];
self.optimizeGames = [[NSUserDefaults standardUserDefaults] boolForKey:@"optimizeGames"];
self.multiController = [[NSUserDefaults standardUserDefaults] boolForKey:@"multipleControllers"];
self.swapABXYButtons = [[NSUserDefaults standardUserDefaults] boolForKey:@"swapABXYButtons"];
self.btMouseSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"btMouseSupport"];
self.statsOverlay = [[NSUserDefaults standardUserDefaults] boolForKey:@"statsOverlay"];
NSInteger _screenSize = [[NSUserDefaults standardUserDefaults] integerForKey:@"streamResolution"];
switch (_screenSize) {
case 0:
self.height = [NSNumber numberWithInteger:720];
self.width = [NSNumber numberWithInteger:1280];
break;
case 1:
self.height = [NSNumber numberWithInteger:1080];
self.width = [NSNumber numberWithInteger:1920];
break;
case 2:
self.height = [NSNumber numberWithInteger:2160];
self.width = [NSNumber numberWithInteger:3840];
break;
case 3:
self.height = [NSNumber numberWithInteger:1440];
self.width = [NSNumber numberWithInteger:2560];
break;
default:
abort();
}
self.onscreenControls = [NSNumber numberWithInteger:OnScreenControlsLevelOff];
#else
self.bitrate = settings.bitrate;
self.framerate = settings.framerate;
self.height = settings.height;
self.width = settings.width;
self.audioConfig = settings.audioConfig;
self.preferredCodec = settings.preferredCodec;
self.useFramePacing = settings.useFramePacing;
self.playAudioOnPC = settings.playAudioOnPC;
self.enableHdr = settings.enableHdr;
self.optimizeGames = settings.optimizeGames;
self.multiController = settings.multiController;
self.swapABXYButtons = settings.swapABXYButtons;
self.onscreenControls = settings.onscreenControls;
self.btMouseSupport = settings.btMouseSupport;
self.absoluteTouchMode = settings.absoluteTouchMode;
self.statsOverlay = settings.statsOverlay;
#endif
self.uniqueId = settings.uniqueId;
return self;

View file

@ -0,0 +1,203 @@
Font data copyright Google 2012
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "limelight_computer_add_icon_1x.png"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "limelight_computer_add_icon_2x.png"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "limelight_computer_add_icon_3x.png"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -1,68 +0,0 @@
%PDF-1.5
%µí®û
4 0 obj
<< /Length 5 0 R
/Filter /FlateDecode
>>
stream
xœ]P[à ûÏ)r<>1}°cìÒº<C392>öcÛý¥AèZ!%q였°/ç"%Èè9oô&áz> _ž—/%qaä!ºyä<79>§T3ÐjqµîaÚ”t„,~Dû›ÖÚGHýôzQõ ®î:xgµ†I6Âß:gP(( hñ¯-1Îü5ç¶Žn3»!&úÖ"˜B-Õ¨~1–@½ZÒ¹](¡¿d÷ë9ا-žt§å…aL
endstream
endobj
5 0 obj
183
endobj
3 0 obj
<<
/ExtGState <<
/a0 << /CA 1 /ca 1 >>
>>
>>
endobj
2 0 obj
<< /Type /Page % 1
/Parent 1 0 R
/MediaBox [ 0 0 150 150 ]
/Contents 4 0 R
/Group <<
/Type /Group
/S /Transparency
/I true
/CS /DeviceRGB
>>
/Resources 3 0 R
>>
endobj
1 0 obj
<< /Type /Pages
/Kids [ 2 0 R ]
/Count 1
>>
endobj
6 0 obj
<< /Producer (cairo 1.16.0 (https://cairographics.org))
/CreationDate (D:20190922201812-07'00)
>>
endobj
7 0 obj
<< /Type /Catalog
/Pages 1 0 R
>>
endobj
xref
0 8
0000000000 65535 f
0000000587 00000 n
0000000369 00000 n
0000000297 00000 n
0000000015 00000 n
0000000275 00000 n
0000000652 00000 n
0000000768 00000 n
trailer
<< /Size 8
/Root 7 0 R
/Info 6 0 R
>>
startxref
820
%%EOF

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -1,21 +0,0 @@
{
"images" : [
{
"filename" : "AltIcon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

View file

@ -13,37 +13,37 @@
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"filename" : "app_icon_settings_58x58_@2x-1.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"filename" : "app_icon_settings_87x87_@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"filename" : "app_icon_spotlight_80x80_@2x-1.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"filename" : "app_icon_spotlight_120x120_@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"filename" : "app_icon_120x120_@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"filename" : "app_icon_180x180_@3x.png",
"scale" : "3x"
},
{
@ -59,50 +59,44 @@
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"filename" : "app_icon_settings_29x29_@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x-1.png",
"filename" : "app_icon_settings_58x58_@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"filename" : "app_icon_spotlight_40x40_@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x-1.png",
"filename" : "app_icon_spotlight_80x80_@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"filename" : "app_icon_76x76_@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"filename" : "app_icon_152x152_@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"filename" : "app_icon_167x167_@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "1024x icon.png",
"scale" : "1x"
}
],
"info" : {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View file

@ -1,71 +0,0 @@
%PDF-1.5
%µí®û
4 0 obj
<< /Length 5 0 R
/Filter /FlateDecode
>>
stream
xœ]‘[ƒ Eÿ³Šl )y¸Œ.¡ÃTû¡µûŸi€ Õa9×›<07>ÑȺ±l.zÌ+|ÀTm›ñþ48a”ä_°äÑ&&ë‘SØ^8cYÕÍÅíl"‹«Æ5ºá‚v¤<76>’"{
ò<9¶<39>j<EFBFBD> ­7Ö!Db ×,Ú<>–PÊbåÐjt¤•øzÅÚœÔ:ƒº,'á½â‚ýÒ‡ wRÁù‘Ê|µ8)’w
-{GÍÑsµ™<C2B5>æ üÞG^’íosû»£MÅkäøà=h_
endstream
endobj
5 0 obj
214
endobj
3 0 obj
<<
/ExtGState <<
/a0 << /CA 0.3 /ca 0.3 >>
/a1 << /CA 1 /ca 1 >>
>>
>>
endobj
2 0 obj
<< /Type /Page % 1
/Parent 1 0 R
/MediaBox [ 0 0 375 375 ]
/Contents 4 0 R
/Group <<
/Type /Group
/S /Transparency
/I true
/CS /DeviceRGB
>>
/Resources 3 0 R
>>
endobj
1 0 obj
<< /Type /Pages
/Kids [ 2 0 R ]
/Count 1
>>
endobj
6 0 obj
<< /Producer (cairo 1.16.0 (https://cairographics.org))
/CreationDate (D:20190922201805-07'00)
>>
endobj
7 0 obj
<< /Type /Catalog
/Pages 1 0 R
>>
endobj
xref
0 8
0000000000 65535 f
0000000650 00000 n
0000000432 00000 n
0000000328 00000 n
0000000015 00000 n
0000000306 00000 n
0000000715 00000 n
0000000831 00000 n
trailer
<< /Size 8
/Root 7 0 R
/Info 6 0 R
>>
startxref
883
%%EOF

View file

@ -2,16 +2,18 @@
"images" : [
{
"idiom" : "universal",
"filename" : "Computer.pdf",
"scale" : "1x"
"scale" : "1x",
"filename" : "limelight_computer_1x.png"
},
{
"idiom" : "universal",
"scale" : "2x"
"scale" : "2x",
"filename" : "limelight_computer_2x.png"
},
{
"idiom" : "universal",
"scale" : "3x"
"scale" : "3x",
"filename" : "limelight_computer_3x.png"
}
],
"info" : {

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Some files were not shown because too many files have changed in this diff Show more