propPath) {
91 | auto j = PVRGetSets();
92 |
93 | for (size_t i = 0; i < propPath.size(); i++) {
94 | if (j.find(propPath[i]) != j.end()) {
95 | j = j[propPath[i]];
96 | if (i == propPath.size() - 1)
97 | return j;
98 | } else
99 | break;
100 | }
101 | std::string fullPath;
102 | j = defSets;
103 | for (size_t i = 0; i < propPath.size(); i++) {
104 | j = j[propPath[i]];
105 | fullPath += propPath[i] + (i < propPath.size() - 1 ? "." : "");
106 | }
107 | T res = j;
108 | PVR_DB_I("Using default setting value: " + fullPath + " = " + to_string(res));
109 | return res;
110 | }
111 |
--------------------------------------------------------------------------------
/code/mobile/android/PhoneVR/app/src/main/java/viritualisres/phonevr/ErrorReportingDialog.java:
--------------------------------------------------------------------------------
1 | /* (C)2023 */
2 | package viritualisres.phonevr;
3 |
4 | import android.app.Activity;
5 | import android.app.AlertDialog;
6 | import android.content.DialogInterface;
7 | import android.graphics.Color;
8 | import android.os.Bundle;
9 | import android.text.Html;
10 | import android.text.method.LinkMovementMethod;
11 | import android.util.Log;
12 | import android.view.View;
13 | import android.widget.TextView;
14 | import androidx.annotation.Nullable;
15 | import java.net.URLEncoder;
16 | import java.util.Objects;
17 | import org.acra.data.CrashReportData;
18 | import org.acra.dialog.CrashReportDialogHelper;
19 |
20 | public class ErrorReportingDialog extends Activity {
21 |
22 | @Override
23 | protected void onCreate(@Nullable Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | // android.os.Debug.waitForDebugger();
26 |
27 | CrashReportDialogHelper helper = new CrashReportDialogHelper(this, getIntent());
28 | try {
29 | getWindow()
30 | .getDecorView()
31 | .setSystemUiVisibility(
32 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
33 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
34 | getWindow().setStatusBarColor(Color.TRANSPARENT);
35 |
36 | CrashReportData reportData = helper.getReportData();
37 |
38 | String ExceptionMsg =
39 | Objects.requireNonNull(reportData.toMap().get("STACK_TRACE")).toString();
40 | ExceptionMsg = ExceptionMsg.substring(0, ExceptionMsg.indexOf("\n"));
41 |
42 | AlertDialog builder =
43 | new AlertDialog.Builder(this)
44 | .setTitle("PVR Crash Handler")
45 | .setIcon(R.mipmap.ic_launcher)
46 | .setMessage(
47 | Html.fromHtml(
48 | "Unfortunately, PhoneVR has been crashed recently."
49 | + " Developers will be"
50 | + " notified.
Exception Message:"
52 | + ExceptionMsg
53 | + "
You can help us by making an issue"
54 | + " in Github's Issue Tracker or by talking to us"
67 | + " directly on Discord."))
69 | .setPositiveButton(
70 | "OK",
71 | new DialogInterface.OnClickListener() {
72 | public void onClick(DialogInterface dialog, int id) {
73 | ErrorReportingDialog.this.finish();
74 | }
75 | })
76 | .create();
77 | builder.setCanceledOnTouchOutside(false);
78 | builder.show();
79 |
80 | ((TextView) builder.findViewById(android.R.id.message))
81 | .setMovementMethod(LinkMovementMethod.getInstance());
82 |
83 | } catch (Exception e) {
84 | Log.d("PVR-Java", "ErrorReportingDialog.OnCreate caught Exception : " + e.getMessage());
85 | e.printStackTrace();
86 | finish();
87 | }
88 | helper.sendCrash("", "");
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/code/mobile/android/PhoneVR/app/src/main/res/layout/activity_init.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
23 |
24 |
36 |
37 |
46 |
53 |
61 |
62 |
63 |
74 |
75 |
86 |
87 |
88 |
99 |
100 |
110 |
111 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/code/mobile/android/PhoneVR/app/src/gvr/java/viritualisres/phonevr/MainActivity.kt:
--------------------------------------------------------------------------------
1 | /* (C)2023 */
2 | package viritualisres.phonevr
3 |
4 | import android.Manifest
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.content.pm.PackageManager
8 | import android.os.Build
9 | import android.os.Bundle
10 | import android.os.Environment.*
11 | import android.util.Log
12 | import android.view.Menu
13 | import android.view.MenuItem
14 | import android.view.WindowManager
15 | import android.widget.TextView
16 | import androidx.appcompat.app.AppCompatActivity
17 | import androidx.appcompat.widget.Toolbar
18 |
19 | class MainActivity : AppCompatActivity() {
20 |
21 | private val REQUEST_CODE: Int = 52142
22 |
23 | override fun onCreate(savedInstanceState: Bundle?) {
24 |
25 | super.onCreate(savedInstanceState)
26 |
27 | // TODO: Add log to file, by making some util
28 | Log.d(
29 | "PhoneVR",
30 | "Running PVR on FINGERPRINT:${Build.FINGERPRINT}\n" +
31 | "MODEL:${Build.MODEL}\n" +
32 | "MANUFACTURER:${Build.MANUFACTURER}\n" +
33 | "BRAND:${Build.BRAND}\n" +
34 | "DEVICE:${Build.DEVICE}\n" +
35 | "BOARD:${Build.BOARD}\n" +
36 | "HOST:${Build.HOST}\n" +
37 | "PRODUCT:${Build.PRODUCT}\n")
38 |
39 | setExtDirinJNI()
40 |
41 | setContentView(R.layout.activity_main)
42 | Wrap.setMainView(this)
43 | window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
44 |
45 | val toolbar: Toolbar = findViewById(R.id.toolbar)
46 | setSupportActionBar(toolbar)
47 |
48 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
49 | when (PackageManager.PERMISSION_DENIED) {
50 | checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) -> {
51 | requestPermissions(
52 | arrayOf(
53 | Manifest.permission.WRITE_EXTERNAL_STORAGE,
54 | Manifest.permission.READ_EXTERNAL_STORAGE),
55 | REQUEST_CODE)
56 | }
57 | }
58 | }
59 |
60 | val VersionTV: TextView = findViewById(R.id.tViewVersion)
61 | VersionTV.text = "PhoneVR v" + BuildConfig.VERSION_NAME
62 |
63 | // MediaCodecInfo[] dmsadas = (new
64 | // MediaCodecList(MediaCodecList.REGULAR_CODECS)).getCodecInfos();
65 | // for (MediaCodecInfo mci : dmsadas){
66 | // if (mci.toString() == "OMX.qcom.video.encoder.avc"){
67 | // mci.getSupportedTypes();
68 | // }
69 | // }
70 |
71 | // MediaCodecList.getCodecInfos();
72 | // Range dsfs = MediaCodecInfo;
73 | // Log.d("PhoneVR", "OnCreate called");
74 | }
75 |
76 | private fun setExtDirinJNI() {
77 | val dir = getExternalFilesDir(null).toString()
78 | Log.d(
79 | "PhoneVR",
80 | "ExtDir: " +
81 | dir +
82 | ", ExtRead Only? :" +
83 | isExternalStorageReadOnly() +
84 | ", ExtAvalb ?:" +
85 | isExternalStorageAvailable())
86 | Wrap.setExtDirectory(dir, dir.length)
87 | }
88 |
89 | private fun isExternalStorageReadOnly(): Boolean {
90 | val extStorageState: String = getExternalStorageState()
91 | return MEDIA_MOUNTED_READ_ONLY == extStorageState
92 | }
93 |
94 | private fun isExternalStorageAvailable(): Boolean {
95 | val extStorageState: String = getExternalStorageState()
96 | return MEDIA_MOUNTED == extStorageState
97 | }
98 |
99 | override fun onRequestPermissionsResult(
100 | requestCode: Int,
101 | permissions: Array,
102 | grantResults: IntArray
103 | ) {
104 | when (requestCode) {
105 | REQUEST_CODE -> {
106 | if ((grantResults.isEmpty() ||
107 | grantResults[0] != PackageManager.PERMISSION_GRANTED) ||
108 | grantResults[1] != PackageManager.PERMISSION_GRANTED) {
109 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
110 | requestPermissions(
111 | arrayOf(
112 | Manifest.permission.WRITE_EXTERNAL_STORAGE,
113 | Manifest.permission.READ_EXTERNAL_STORAGE),
114 | REQUEST_CODE)
115 | }
116 | } else setExtDirinJNI()
117 | return
118 | }
119 | else -> {
120 | // Ignore all other requests.
121 | }
122 | }
123 | }
124 |
125 | override fun onResume() {
126 | super.onResume()
127 | setExtDirinJNI()
128 | val prefs = getSharedPreferences(pvrPrefsKey, Context.MODE_PRIVATE)
129 | // Wrap.startAnnouncer(prefs.getString(pcIpKey, pcIpDef), prefs.getInt(connPortKey,
130 | // connPortDef))
131 |
132 | // Log.d("PhoneVR", "OnResume called... Starting Announcer @ port :" +
133 | // prefs.getInt(connPortKey,
134 | // connPortDef).toString());
135 | prefs.getString(pcIpKey, pcIpDef)?.let {
136 | Wrap.startAnnouncer(it, prefs.getInt(connPortKey, connPortDef))
137 | }
138 | }
139 |
140 | override fun onPause() {
141 | super.onPause()
142 | Wrap.stopAnnouncer()
143 | }
144 |
145 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
146 | menuInflater.inflate(R.menu.main, menu)
147 | return true
148 | }
149 |
150 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
151 | if (item.itemId == R.id.action_settings) {
152 | val intent = Intent(this, SettingsActivity::class.java)
153 | startActivity(intent)
154 | return true
155 | }
156 |
157 | return super.onOptionsItemSelected(item)
158 | }
159 |
160 | companion object {
161 | init {
162 | // check if android supports x86 abi
163 | if (Build.SUPPORTED_ABIS.contains("x86") ||
164 | Build.SUPPORTED_ABIS.contains("arm64-v8a") ||
165 | Build.SUPPORTED_ABIS.contains("armeabi-v7a"))
166 | System.loadLibrary("native-lib-gvr")
167 | }
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/code/common/src/PVRGlobals.cpp:
--------------------------------------------------------------------------------
1 | #include "PVRGlobals.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | using namespace std;
9 | using namespace std::chrono;
10 |
11 | PVR_STATE pvrState = PVR_STATE_IDLE;
12 |
13 | // void timeStart() {
14 | // _time = Clk::now();
15 | // }
16 | //
17 | // void printTime() {
18 | // printf("%i\n", (int)duration_cast(Clk::now() - _time).count());
19 | // }
20 |
21 | //////// only windows /////////
22 | #ifdef _WIN32
23 | #define WIN32_LEAN_AND_MEAN
24 | #include
25 |
26 | namespace {
27 | int64_t pvrdebug_oldMs = 0;
28 | int64_t pvrInfo_oldMs = 0;
29 |
30 | const wstring logFileDebug = L"\\..\\..\\drivers\\PVRServer\\logs\\pvrDebuglog.txt";
31 | const wstring logFileInfo = L"\\..\\..\\drivers\\PVRServer\\logs\\pvrlog.txt";
32 | } // namespace
33 |
34 | std::wstring _GetExePath(void) {
35 | TCHAR buffer[MAX_PATH] = {0};
36 | GetModuleFileName(NULL, buffer, MAX_PATH);
37 | std::wstring::size_type pos = std::wstring(buffer).find_last_of(L"\\/");
38 | return std::wstring(buffer).substr(0, pos);
39 | }
40 |
41 | void pvrdebug(string msg) {
42 | SYSTEMTIME t;
43 | GetLocalTime(&t);
44 | ofstream of(std::wstring(_GetExePath() + logFileDebug).c_str(), ios_base::app);
45 | auto ms = system_clock::now().time_since_epoch() / 1ms;
46 | string elapsed = (ms - pvrdebug_oldMs < 1000 ? to_string(ms - pvrdebug_oldMs) : "max");
47 | of << t.wMinute << ":" << setfill('0') << setw(2) << t.wSecond << " " << setfill('0') << setw(3)
48 | << elapsed << " " << msg << endl;
49 |
50 | OutputDebugStringA(("--[PhoneVR]--" + msg + "\n").c_str());
51 |
52 | pvrdebug_oldMs = ms;
53 | }
54 |
55 | void pvrdebugClear() {
56 | ofstream(std::wstring(_GetExePath() + logFileDebug).c_str(), ofstream::out | ofstream::trunc);
57 | }
58 |
59 | void pvrInfo(string msg) {
60 | SYSTEMTIME t;
61 | GetLocalTime(&t);
62 | ofstream of(std::wstring(_GetExePath() + logFileInfo).c_str(), ios_base::app);
63 | auto ms = system_clock::now().time_since_epoch() / 1ms;
64 | string elapsed = (ms - pvrInfo_oldMs < 1000 ? to_string(ms - pvrInfo_oldMs) : "max");
65 | of << setfill('0') << setw(2) << t.wHour << ":" << setfill('0') << setw(2) << t.wMinute << ":"
66 | << setfill('0') << setw(2) << t.wSecond << "(" << setfill('0') << setw(3) << t.wMilliseconds
67 | << ") - " << setfill('0') << setw(2) << t.wDay << "." << setfill('0') << setw(2) << t.wMonth
68 | << "." << setfill('0') << setw(4) << t.wYear << " -- " << setfill('0') << setw(2)
69 | << t.wSecond << " " << setfill('0') << setw(3) << elapsed << " " << msg << endl;
70 | pvrInfo_oldMs = ms;
71 | }
72 | #endif
73 |
74 | //////// only android //////
75 | #ifdef __ANDROID__
76 | #include
77 | #include
78 |
79 | using namespace std;
80 | extern char *ExtDirectory;
81 |
82 | void pvrInfo(string msg) {
83 | try {
84 | if (ExtDirectory != nullptr) {
85 | auto *file = fopen(
86 | string(string(ExtDirectory).c_str() + string("/PVR/pvrlog.txt")).c_str(), "a");
87 |
88 | std::time_t nowtime =
89 | std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
90 | struct tm *time = localtime(&nowtime);
91 |
92 | if (file) {
93 | fprintf(file,
94 | "%02d:%02d:%02d-%02d.%02d.%04d - PVR-JNI-I: %s\n",
95 | time->tm_hour,
96 | time->tm_min,
97 | time->tm_sec,
98 | time->tm_mday,
99 | 1 + time->tm_mon,
100 | 1900 + time->tm_year,
101 | msg.c_str());
102 | fclose(file);
103 | } else if (file == NULL) {
104 | __android_log_print(ANDROID_LOG_DEBUG,
105 | "PVR-JNI-D",
106 | "PVRGlobals_pvrInfo:: fopen returned NULL value");
107 | }
108 | }
109 | } catch (exception e) {
110 | //__android_log_print(ANDROID_LOG_DEBUG, "PVR-JNI-D", "PVRGlobals_pvrInfo:: Caught
111 | // Exception: " + string(e.what()));
112 | } catch (...) {
113 | //__android_log_print(ANDROID_LOG_DEBUG, "PVR-JNI-D", "PVRGlobals_pvrInfo:: Caught
114 | // Exception: from Generic Handler");
115 | }
116 | }
117 |
118 | void pvrdebug(string msg) {
119 | __android_log_print(ANDROID_LOG_DEBUG, "PVR-JNI-D", "%s", msg.c_str());
120 |
121 | try {
122 | if (ExtDirectory != nullptr) {
123 | auto *file = fopen(string(string(ExtDirectory) + "/PVR/pvrDebuglog.txt").c_str(), "a");
124 |
125 | std::time_t nowtime =
126 | std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
127 | struct tm *time = localtime(&nowtime);
128 |
129 | if (file) {
130 | fprintf(file,
131 | "%02d:%02d:%02d-%02d.%02d.%04d - PVR-JNI-D: %s\n",
132 | time->tm_hour,
133 | time->tm_min,
134 | time->tm_sec,
135 | time->tm_mday,
136 | 1 + time->tm_mon,
137 | 1900 + time->tm_year,
138 | msg.c_str());
139 | fclose(file);
140 | //__android_log_print(ANDROID_LOG_DEBUG, "PVR-JNI-D", "Wrote in File: %s - %s",
141 | // string(ExtDirectory).c_str(), string(string(ExtDirectory) +
142 | // string("/PVR/pvrlog.txt")).c_str());
143 | } else {
144 | __android_log_print(
145 | ANDROID_LOG_DEBUG,
146 | "PVR-JNI-D",
147 | "File Error %d (%s): %s - %s",
148 | errno,
149 | string(ExtDirectory).c_str(),
150 | string(string(ExtDirectory) + string("/PVR/pvrlog.txt")).c_str(),
151 | strerror(errno));
152 | }
153 | }
154 | } catch (exception e) {
155 | //__android_log_print(ANDROID_LOG_DEBUG, "PVR-JNI-D", "PVRGlobals_pvrInfo:: Caught
156 | // Exception: " + string(e.what()));
157 | } catch (...) {
158 | //__android_log_print(ANDROID_LOG_DEBUG, "PVR-JNI-D", "PVRGlobals_pvrInfo:: Caught
159 | // Exception: from Generic Handler");
160 | }
161 | }
162 |
163 | #endif
164 |
--------------------------------------------------------------------------------
/code/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | ## Android studio
3 | *.iml
4 | .gradle
5 | /local.properties
6 | /.idea/workspace.xml
7 | /.idea/libraries
8 | .DS_Store
9 | /build
10 | /captures
11 | .externalNativeBuild
12 |
13 |
14 |
15 | ## Ignore Visual Studio temporary files, build results, and
16 | ## files generated by popular Visual Studio add-ons.
17 | ##
18 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
19 |
20 | # User-specific files
21 | *.suo
22 | *.user
23 | *.userosscache
24 | *.sln.docstates
25 |
26 | # User-specific files (MonoDevelop/Xamarin Studio)
27 | *.userprefs
28 |
29 | # Build results
30 | [Dd]ebug/
31 | [Dd]ebugPublic/
32 | [Rr]elease/
33 | [Rr]eleases/
34 | x64/
35 | x86/
36 | bld/
37 | [Bb]in/
38 | [Oo]bj/
39 | [Ll]og/
40 |
41 | !windows/libs/x264/lib/x64/
42 | !windows/libs/x264/lib/x86/
43 | !mobile/android/libraries/jni/x86
44 |
45 | # Visual Studio 2015 cache/options directory
46 | .vs/
47 | # Uncomment if you have tasks that create the project's static files in wwwroot
48 | #wwwroot/
49 |
50 | # MSTest test Results
51 | [Tt]est[Rr]esult*/
52 | [Bb]uild[Ll]og.*
53 |
54 | # NUNIT
55 | *.VisualState.xml
56 | TestResult.xml
57 |
58 | # Build Results of an ATL Project
59 | [Dd]ebugPS/
60 | [Rr]eleasePS/
61 | dlldata.c
62 |
63 | # Benchmark Results
64 | BenchmarkDotNet.Artifacts/
65 |
66 | # .NET Core
67 | project.lock.json
68 | project.fragment.lock.json
69 | artifacts/
70 | **/Properties/launchSettings.json
71 |
72 | *_i.c
73 | *_p.c
74 | *_i.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.pch
79 | *.pdb
80 | *.pgc
81 | *.pgd
82 | *.rsp
83 | *.sbr
84 | *.tlb
85 | *.tli
86 | *.tlh
87 | *.tmp
88 | *.tmp_proj
89 | *.log
90 | *.vspscc
91 | *.vssscc
92 | .builds
93 | *.pidb
94 | *.svclog
95 | *.scc
96 |
97 | # Chutzpah Test files
98 | _Chutzpah*
99 |
100 | # Visual C++ cache files
101 | ipch/
102 | *.aps
103 | *.ncb
104 | *.opendb
105 | *.opensdf
106 | *.sdf
107 | *.cachefile
108 | *.VC.db
109 | *.VC.VC.opendb
110 |
111 | # Visual Studio profiler
112 | *.psess
113 | *.vsp
114 | *.vspx
115 | *.sap
116 |
117 | # TFS 2012 Local Workspace
118 | $tf/
119 |
120 | # Guidance Automation Toolkit
121 | *.gpState
122 |
123 | # ReSharper is a .NET coding add-in
124 | _ReSharper*/
125 | *.[Rr]e[Ss]harper
126 | *.DotSettings.user
127 |
128 | # JustCode is a .NET coding add-in
129 | .JustCode
130 |
131 | # TeamCity is a build add-in
132 | _TeamCity*
133 |
134 | # DotCover is a Code Coverage Tool
135 | *.dotCover
136 |
137 | # AxoCover is a Code Coverage Tool
138 | .axoCover/*
139 | !.axoCover/settings.json
140 |
141 | # Visual Studio code coverage results
142 | *.coverage
143 | *.coveragexml
144 |
145 | # NCrunch
146 | _NCrunch_*
147 | .*crunch*.local.xml
148 | nCrunchTemp_*
149 |
150 | # MightyMoose
151 | *.mm.*
152 | AutoTest.Net/
153 |
154 | # Web workbench (sass)
155 | .sass-cache/
156 |
157 | # Installshield output folder
158 | [Ee]xpress/
159 |
160 | # DocProject is a documentation generator add-in
161 | DocProject/buildhelp/
162 | DocProject/Help/*.HxT
163 | DocProject/Help/*.HxC
164 | DocProject/Help/*.hhc
165 | DocProject/Help/*.hhk
166 | DocProject/Help/*.hhp
167 | DocProject/Help/Html2
168 | DocProject/Help/html
169 |
170 | # Click-Once directory
171 | publish/
172 |
173 | # Publish Web Output
174 | *.[Pp]ublish.xml
175 | *.azurePubxml
176 | # Note: Comment the next line if you want to checkin your web deploy settings,
177 | # but database connection strings (with potential passwords) will be unencrypted
178 | *.pubxml
179 | *.publishproj
180 |
181 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
182 | # checkin your Azure Web App publish settings, but sensitive information contained
183 | # in these scripts will be unencrypted
184 | PublishScripts/
185 |
186 | # NuGet Packages
187 | *.nupkg
188 | # The packages folder can be ignored because of Package Restore
189 | **/packages/*
190 | # except build/, which is used as an MSBuild target.
191 | !**/packages/build/
192 | # Uncomment if necessary however generally it will be regenerated when needed
193 | #!**/packages/repositories.config
194 | # NuGet v3's project.json files produces more ignorable files
195 | *.nuget.props
196 | *.nuget.targets
197 |
198 | # Microsoft Azure Build Output
199 | csx/
200 | *.build.csdef
201 |
202 | # Microsoft Azure Emulator
203 | ecf/
204 | rcf/
205 |
206 | # Windows Store app package directories and files
207 | AppPackages/
208 | BundleArtifacts/
209 | Package.StoreAssociation.xml
210 | _pkginfo.txt
211 | *.appx
212 |
213 | # Visual Studio cache files
214 | # files ending in .cache can be ignored
215 | *.[Cc]ache
216 | # but keep track of directories ending in .cache
217 | !*.[Cc]ache/
218 |
219 | # Others
220 | ClientBin/
221 | ~$*
222 | *~
223 | *.dbmdl
224 | *.dbproj.schemaview
225 | *.jfm
226 | *.pfx
227 | *.publishsettings
228 | orleans.codegen.cs
229 |
230 | # Since there are multiple workflows, uncomment next line to ignore bower_components
231 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
232 | #bower_components/
233 |
234 | # RIA/Silverlight projects
235 | Generated_Code/
236 |
237 | # Backup & report files from converting an old project file
238 | # to a newer Visual Studio version. Backup files are not needed,
239 | # because we have git ;-)
240 | _UpgradeReport_Files/
241 | Backup*/
242 | UpgradeLog*.XML
243 | UpgradeLog*.htm
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 |
255 | # Microsoft Fakes
256 | FakesAssemblies/
257 |
258 | # GhostDoc plugin setting file
259 | *.GhostDoc.xml
260 |
261 | # Node.js Tools for Visual Studio
262 | .ntvs_analysis.dat
263 | node_modules/
264 |
265 | # Typescript v1 declaration files
266 | typings/
267 |
268 | # Visual Studio 6 build log
269 | *.plg
270 |
271 | # Visual Studio 6 workspace options file
272 | *.opt
273 |
274 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
275 | *.vbw
276 |
277 | # Visual Studio LightSwitch build output
278 | **/*.HTMLClient/GeneratedArtifacts
279 | **/*.DesktopClient/GeneratedArtifacts
280 | **/*.DesktopClient/ModelManifest.xml
281 | **/*.Server/GeneratedArtifacts
282 | **/*.Server/ModelManifest.xml
283 | _Pvt_Extensions
284 |
285 | # Paket dependency manager
286 | .paket/paket.exe
287 | paket-files/
288 |
289 | # FAKE - F# Make
290 | .fake/
291 |
292 | # JetBrains Rider
293 | .idea/
294 | *.sln.iml
295 |
296 | # CodeRush
297 | .cr/
298 |
299 | # Python Tools for Visual Studio (PTVS)
300 | __pycache__/
301 | *.pyc
302 |
303 | # Cake - Uncomment if you are using it
304 | # tools/**
305 | # !tools/packages.config
306 |
307 | # Tabs Studio
308 | *.tss
309 |
310 | # Telerik's JustMock configuration file
311 | *.jmconfig
312 |
313 | # BizTalk build output
314 | *.btp.cs
315 | *.btm.cs
316 | *.odx.cs
317 | *.xsd.cs
318 |
319 | .cxx
--------------------------------------------------------------------------------
/code/common/src/PVRSocketUtils.cpp:
--------------------------------------------------------------------------------
1 | #include "PVRSocketUtils.h"
2 | #include
3 |
4 | using namespace std;
5 | using namespace std::this_thread;
6 | using namespace asio;
7 | using namespace asio::ip;
8 | using namespace std::chrono;
9 |
10 | // packetize TCP stream: "pvr" / msg type byte / data size (2 bytes) / data
11 | // prefix -> 6 bytes
12 |
13 | TCPTalker::TCPTalker(uint16_t port,
14 | function)> recCb,
15 | function errCb,
16 | bool isServer,
17 | string ip) {
18 | bool initted = false;
19 | PVR_DB_I("[TCPTalker::TCPTalker] Init'ed with p:" + to_string(port) +
20 | " isServer:" + to_string(isServer) + " ip:" + to_string(ip))
21 |
22 | thr = new std::thread([=, &initted] {
23 | try {
24 | io_service svc;
25 | tcp::socket skt(svc);
26 | _skt = &skt;
27 | tcp::acceptor acc(svc, {tcp::v4(), port});
28 |
29 | asio::error_code ec = asio::error::fault;
30 | auto errHdl = [&](const asio::error_code &err) { ec = err; };
31 | if (isServer) { // talker is a server; Mobile device will be Announcing UDP + Will be
32 | // Server
33 | if (ip.empty()) {
34 | acc.async_accept(skt, errHdl); // todo: simplify
35 | PVR_DB_I("[TCPTalker::TCPTalker] Talker is Server and ip is Empty. Accepting "
36 | "All connection...");
37 | } else {
38 | acc.async_accept(skt, errHdl); // todo: simplify
39 | // skt.async_connect({ address::from_string(ip), port }, errHdl);
40 | PVR_DB_I("[TCPTalker::TCPTalker] Talker is Server and Accepting connections "
41 | "from ip:" +
42 | ip + " & port:" + to_string(port) + "...");
43 | }
44 | initted = true; // early unblock server
45 | } else // talker is a client; Desktop will be Client will receive the Announcement +
46 | // Will try to connect.
47 | {
48 | skt.async_connect({address::from_string(ip), port}, errHdl);
49 | PVR_DB_I("[TCPTalker::TCPTalker] Talker is Client and Connecting to ip:" + ip +
50 | " & port:" + to_string(port) + "...");
51 | }
52 | svc.run();
53 | svc.reset();
54 | if (!isServer)
55 | initted = true; // on server mode this goes out of scope
56 |
57 | if (ec.value() == 0) {
58 | IP = skt.remote_endpoint().address().to_string();
59 |
60 | const size_t bufsz = 256;
61 | string prefix = "pvr";
62 | uint8_t buf[bufsz];
63 | vector stream;
64 | size_t msgLen = 0;
65 |
66 | function handle = [&](const asio::error_code
67 | & /*err*/,
68 | size_t len) {
69 | // PVR_DB_I("[TCPTalker::TCPTalker] Revd some data... Interpreting...");
70 | stream.insert(stream.end(), buf, buf + len);
71 | bool loop = true;
72 | while (loop) {
73 | auto it = find_first_of(
74 | stream.begin(), stream.end(), prefix.begin(), prefix.end());
75 | if (stream.end() - it >= 6) {
76 | msgLen = size_t(*(it + 4)) + size_t(*(it + 5)) * 0x100;
77 | it += 6; // skip prefix
78 | if (stream.size() >=
79 | it - stream.begin() +
80 | msgLen) { // warning! do not increment iterator out of bounds
81 | recCb(PVR_MSG(*(it - 3)), vector(it, it + msgLen));
82 | stream.erase(stream.begin(), it + msgLen);
83 | } else
84 | loop = false;
85 | } else
86 | loop = false;
87 | }
88 | skt.async_read_some(buffer(buf, bufsz), handle);
89 | };
90 | skt.async_read_some(buffer(buf, bufsz), handle);
91 | PVR_DB_I("[TCPTalker::TCPTalker] Talker is Connected. Trying to read some data...");
92 | svc.run();
93 | }
94 | if (ec.value() != 0)
95 | errCb(ec);
96 |
97 | sktMtx.lock();
98 | skt.close();
99 | _skt = nullptr;
100 | sktMtx.unlock();
101 | } catch (exception &e) {
102 | PVR_DB_I("[TCPTalker::TCPTalker] Exception caught: " + string(e.what()));
103 | }
104 | });
105 | while (!initted)
106 | sleep_for(milliseconds(2));
107 | }
108 |
109 | void TCPTalker::safeDispatch(function hdl) {
110 | try {
111 | sktMtx.lock();
112 | if (_skt) {
113 | bool done = false;
114 | _skt->get_io_service().dispatch([&] {
115 | hdl();
116 | done = true;
117 | });
118 | while (!done)
119 | sleep_for(milliseconds(10));
120 | }
121 | sktMtx.unlock();
122 | } catch (exception &e) {
123 | PVR_DB_I("[TCPTalker::safeDispatch] Exception caught: " + string(e.what()));
124 | }
125 | }
126 |
127 | bool TCPTalker::send(PVR_MSG msgType, vector data) {
128 | vector buf = {'p', 'v', 'r', (uint8_t) msgType, 0, 0};
129 | auto sz = data.size();
130 | memcpy(&buf[4], &sz, 2);
131 | buf.insert(buf.end(), data.begin(), data.end());
132 |
133 | bool success = false;
134 | safeDispatch([&] {
135 | if (_skt->is_open()) {
136 | asio::error_code ec;
137 | write(*_skt, buffer(buf), ec);
138 | success = ec.value() == 0;
139 | if (ec.value()) {
140 | PVR_DB_I("[TCPTalker::send] Error Sending EC(" + to_string(ec.value()) +
141 | "): " + ec.message());
142 | } else {
143 | PVR_DB_I("[TCPTalker::send] Msg Sent with ID:" + to_string(buf[3]));
144 | }
145 | } else {
146 | PVR_DB_I("[TCPTalker::send] Error Sending: Socket is not open");
147 | }
148 | });
149 | return success;
150 | }
151 |
152 | TCPTalker::~TCPTalker() {
153 | safeDispatch([=] { _skt->get_io_service().stop(); });
154 | EndThread(thr);
155 | }
156 |
157 | typedef unsigned long uint32;
158 |
159 | uint32 SockAddrToUint32(struct sockaddr *a) {
160 | return ((a) && (a->sa_family == AF_INET)) ? ntohl(((struct sockaddr_in *) a)->sin_addr.s_addr)
161 | : 0;
162 | }
163 |
164 | // convert a numeric IP address into its string representation
165 | void Inet_NtoA(uint32 addr, char *ipbuf) {
166 | sprintf(ipbuf,
167 | "%li.%li.%li.%li",
168 | (addr >> 24) & 0xFF,
169 | (addr >> 16) & 0xFF,
170 | (addr >> 8) & 0xFF,
171 | (addr >> 0) & 0xFF);
172 | }
--------------------------------------------------------------------------------
/code/common/libs/ifaddrs/pvr_google_ifaddrs.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2009 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | #ifndef IFADDRS_ANDROID_H_included
17 | #define IFADDRS_ANDROID_H_included
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include "LocalArray.h"
31 | #include "ScopedFd.h"
32 | // Android (bionic) doesn't have getifaddrs(3)/freeifaddrs(3).
33 | // We fake it here, so java_net_NetworkInterface.cpp can use that API
34 | // with all the non-portable code being in this file.
35 | // Source-compatible subset of the BSD struct.
36 | struct ifaddrs {
37 | // Pointer to next struct in list, or NULL at end.
38 | ifaddrs* ifa_next;
39 | // Interface name.
40 | char* ifa_name;
41 | // Interface flags.
42 | unsigned int ifa_flags;
43 | // Interface network address.
44 | sockaddr* ifa_addr;
45 | // Interface netmask.
46 | sockaddr* ifa_netmask;
47 | ifaddrs(ifaddrs* next)
48 | : ifa_next(next), ifa_name(NULL), ifa_flags(0), ifa_addr(NULL), ifa_netmask(NULL)
49 | {
50 | }
51 | ~ifaddrs() {
52 | delete ifa_next;
53 | delete[] ifa_name;
54 | delete ifa_addr;
55 | delete ifa_netmask;
56 | }
57 | // Sadly, we can't keep the interface index for portability with BSD.
58 | // We'll have to keep the name instead, and re-query the index when
59 | // we need it later.
60 | bool setNameAndFlagsByIndex(int interfaceIndex) {
61 | // Get the name.
62 | char buf[IFNAMSIZ];
63 | char* name = if_indextoname(interfaceIndex, buf);
64 | if (name == NULL) {
65 | return false;
66 | }
67 | ifa_name = new char[strlen(name) + 1];
68 | strcpy(ifa_name, name);
69 | // Get the flags.
70 | ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0));
71 | if (fd.get() == -1) {
72 | return false;
73 | }
74 | ifreq ifr;
75 | memset(&ifr, 0, sizeof(ifr));
76 | strcpy(ifr.ifr_name, name);
77 | int rc = ioctl(fd.get(), SIOCGIFFLAGS, &ifr);
78 | if (rc == -1) {
79 | return false;
80 | }
81 | ifa_flags = ifr.ifr_flags;
82 | return true;
83 | }
84 | // Netlink gives us the address family in the header, and the
85 | // sockaddr_in or sockaddr_in6 bytes as the payload. We need to
86 | // stitch the two bits together into the sockaddr that's part of
87 | // our portable interface.
88 | void setAddress(int family, void* data, size_t byteCount) {
89 | // Set the address proper...
90 | sockaddr_storage* ss = new sockaddr_storage;
91 | memset(ss, 0, sizeof(*ss));
92 | ifa_addr = reinterpret_cast(ss);
93 | ss->ss_family = family;
94 | uint8_t* dst = sockaddrBytes(family, ss);
95 | memcpy(dst, data, byteCount);
96 | }
97 | // Netlink gives us the prefix length as a bit count. We need to turn
98 | // that into a BSD-compatible netmask represented by a sockaddr*.
99 | void setNetmask(int family, size_t prefixLength) {
100 | // ...and work out the netmask from the prefix length.
101 | sockaddr_storage* ss = new sockaddr_storage;
102 | memset(ss, 0, sizeof(*ss));
103 | ifa_netmask = reinterpret_cast(ss);
104 | ss->ss_family = family;
105 | uint8_t* dst = sockaddrBytes(family, ss);
106 | memset(dst, 0xff, prefixLength / 8);
107 | if ((prefixLength % 8) != 0) {
108 | dst[prefixLength/8] = (0xff << (8 - (prefixLength % 8)));
109 |
110 | }
111 | }
112 | // Returns a pointer to the first byte in the address data (which is
113 | // stored in network byte order).
114 | uint8_t* sockaddrBytes(int family, sockaddr_storage* ss) {
115 | if (family == AF_INET) {
116 | sockaddr_in* ss4 = reinterpret_cast(ss);
117 | return reinterpret_cast(&ss4->sin_addr);
118 | } else if (family == AF_INET6) {
119 | sockaddr_in6* ss6 = reinterpret_cast(ss);
120 | return reinterpret_cast(&ss6->sin6_addr);
121 | }
122 | return NULL;
123 | }
124 | private:
125 | // Disallow copy and assignment.
126 | ifaddrs(const ifaddrs&);
127 | void operator=(const ifaddrs&);
128 | };
129 | // FIXME: use iovec instead.
130 | struct addrReq_struct {
131 | nlmsghdr netlinkHeader;
132 | ifaddrmsg msg;
133 | };
134 | inline bool sendNetlinkMessage(int fd, const void* data, size_t byteCount) {
135 | ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(fd, data, byteCount, 0));
136 | return (sentByteCount == static_cast(byteCount));
137 | }
138 | inline ssize_t recvNetlinkMessage(int fd, char* buf, size_t byteCount) {
139 | return TEMP_FAILURE_RETRY(recv(fd, buf, byteCount, 0));
140 | }
141 | // Source-compatible with the BSD function.
142 | inline int getifaddrs(ifaddrs** result) {
143 | // Simplify cleanup for callers.
144 | *result = NULL;
145 | // Create a netlink socket.
146 | ScopedFd fd(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE));
147 | if (fd.get() < 0) {
148 | return -1;
149 | }
150 | // Ask for the address information.
151 | addrReq_struct addrRequest;
152 | memset(&addrRequest, 0, sizeof(addrRequest));
153 | addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
154 | addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR;
155 | addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest)));
156 | addrRequest.msg.ifa_family = AF_UNSPEC; // All families.
157 | addrRequest.msg.ifa_index = 0; // All interfaces.
158 | if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) {
159 | return -1;
160 | }
161 | // Read the responses.
162 | LocalArray<0> buf(65536); // We don't necessarily have std::vector.
163 | ssize_t bytesRead;
164 | while ((bytesRead = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) {
165 | nlmsghdr* hdr = reinterpret_cast(&buf[0]);
166 | for (; NLMSG_OK(hdr, (size_t)bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) {
167 | switch (hdr->nlmsg_type) {
168 | case NLMSG_DONE:
169 | return 0;
170 | case NLMSG_ERROR:
171 | return -1;
172 | case RTM_NEWADDR:
173 | {
174 | ifaddrmsg* address = reinterpret_cast(NLMSG_DATA(hdr));
175 | rtattr* rta = IFA_RTA(address);
176 | size_t ifaPayloadLength = IFA_PAYLOAD(hdr);
177 | while (RTA_OK(rta, ifaPayloadLength)) {
178 | if (rta->rta_type == IFA_LOCAL) {
179 | int family = address->ifa_family;
180 | if (family == AF_INET || family == AF_INET6) {
181 | *result = new ifaddrs(*result);
182 | if (!(*result)->setNameAndFlagsByIndex(address->ifa_index)) {
183 | return -1;
184 | }
185 | (*result)->setAddress(family, RTA_DATA(rta), RTA_PAYLOAD(rta));
186 | (*result)->setNetmask(family, address->ifa_prefixlen);
187 | }
188 | }
189 | rta = RTA_NEXT(rta, ifaPayloadLength);
190 | }
191 | }
192 | break;
193 | }
194 | }
195 | }
196 | // We only get here if recv fails before we see a NLMSG_DONE.
197 | return -1;
198 | }
199 | // Source-compatible with the BSD function.
200 | inline void freeifaddrs(ifaddrs* addresses) {
201 | delete addresses;
202 | }
203 | #endif // IFADDRS_ANDROID_H_included
204 |
--------------------------------------------------------------------------------
/code/mobile/android/PhoneVR/app/build.gradle:
--------------------------------------------------------------------------------
1 | import com.android.build.gradle.internal.dsl.PackagingOptions
2 |
3 | apply plugin: 'com.android.application'
4 | apply plugin: 'kotlin-android'
5 | apply plugin: 'com.android.application'
6 | apply plugin: 'com.google.gms.google-services'
7 | apply from: '../versioning.gradle'
8 | apply plugin: "com.diffplug.spotless"
9 |
10 | def keystorePropertiesFile = rootProject.file("keystore.properties")
11 | def keystoreProperties = new Properties()
12 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
13 |
14 | def defaultALVRFlavour = "--release"
15 |
16 | android {
17 | signingConfigs {
18 | releaseconfig {
19 | if( System.getenv('GITHUB_EVENT_NAME') == 'pull_request' || System.getenv("Store") == null || System.getenv("Key") == null ) {
20 | // If its a PR Supply a dummy KeySigningConfig
21 | // Or in Local env if Store and Keys are not present in ENV Vars do the same
22 | storeFile file("PhoneVRKeyStorePR.jks")
23 | storePassword "test1234"
24 | keyAlias "PhoneVRKeyPR"
25 | keyPassword "test1234"
26 | println "[PVR] Configuring releaseconfigs for testing a PR..."
27 | }
28 | else {
29 | storeFile file(keystoreProperties['storeFile'])
30 | storePassword System.getenv("Store")
31 | keyAlias keystoreProperties['keyAlias']
32 | keyPassword System.getenv("Key")
33 | println "[PVR] Configuring releaseconfigs for release (push) (not a PR)"
34 | }
35 | }
36 | }
37 | compileSdkVersion 34
38 | namespace 'viritualisres.phonevr'
39 | ndkVersion '25.2.9519653' // r25c
40 | defaultConfig {
41 | applicationId "viritualisres.phonevr"
42 | minSdkVersion 24
43 | targetSdkVersion 33
44 | versionCode buildVersionCode()
45 | versionName buildVersionName()
46 |
47 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
48 | testInstrumentationRunnerArguments useTestStorageService: 'true'
49 |
50 | externalNativeBuild {
51 | cmake {
52 | cppFlags "-std=c++17 -fexceptions -frtti" //-DANDROID_USE_LEGACY_TOOLCHAIN_FILE=ON"
53 | }
54 | }
55 |
56 | defaultPublishConfig 'release'
57 | publishNonDefault true
58 | archivesBaseName = "PhoneVR-v$versionName"
59 | }
60 | buildTypes {
61 | release {
62 | minifyEnabled false
63 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
64 | debuggable false
65 | signingConfig signingConfigs.releaseconfig
66 | }
67 | debug {
68 | debuggable true
69 | jniDebuggable true
70 | renderscriptDebuggable true
71 | minifyEnabled false
72 | externalNativeBuild {
73 | cmake {
74 | cppFlags += "-D_DEBUG=1"
75 | }
76 | }
77 | defaultALVRFlavour = ""
78 | }
79 | }
80 | buildFeatures {
81 | buildConfig = true // TODO: Remove BuildConfig, Gradle suggests this usage is inefficient > v8 disabled by default
82 | viewBinding true
83 | }
84 | flavorDimensions "gvr"
85 | productFlavors {
86 | gvr {
87 | dimension "gvr"
88 | externalNativeBuild {
89 | cmake {
90 | arguments "-D HAVEGVR=true"
91 | }
92 | }
93 | }
94 | noGvr {
95 | dimension "gvr"
96 | versionNameSuffix "-nogvr"
97 | }
98 | }
99 | sourceSets {
100 | main {
101 | jniLibs.srcDirs = ["libraries/jni", "../ALVR/build/alvr_client_core"]
102 | }
103 | gvr {
104 | jniLibs.srcDirs = ["libraries/jni", "libraries_gvr/jni", "../ALVR/build/alvr_client_core"]
105 | }
106 | }
107 | externalNativeBuild {
108 | cmake {
109 | // version "3.6.4"
110 | path "CMakeLists.txt"
111 | }
112 | }
113 | project.gradle.taskGraph.whenReady {
114 | android.productFlavors.all { flavor ->
115 | // Capitalize (as Gralde is case-sensitive).
116 | def flavorName = flavor.name.substring(0, 1).toUpperCase() + flavor.name.substring(1)
117 |
118 | // At last, configure.
119 | "connected${flavorName}DebugAndroidTest" {
120 | ignoreFailures = true
121 | }
122 | }
123 | }
124 |
125 | // CompileOptions required for ARCA
126 | compileOptions {
127 | sourceCompatibility JavaVersion.VERSION_1_8
128 | targetCompatibility JavaVersion.VERSION_1_8
129 | }
130 | kotlinOptions {
131 | jvmTarget = '1.8'
132 | }
133 |
134 | packagingOptions {
135 | jniLibs.useLegacyPackaging = true
136 | gradle.startParameter.getTaskNames().each { task ->
137 | println("[PVR] task is " + task)
138 | if (task.contains('debug') || task.contains('Debug')) {
139 | def android = project.extensions.findByName("android")
140 |
141 | if(android != null) {
142 | PackagingOptions packagingOptions = android["packagingOptions"]
143 |
144 | if (packagingOptions != null) {
145 | packagingOptions.doNotStrip = [ "**/*.so" ]
146 | }
147 | }
148 | }
149 | }
150 | }
151 | }
152 |
153 | dependencies {
154 | implementation fileTree(dir: 'libs', include: ['*.jar'])
155 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
156 | implementation 'androidx.appcompat:appcompat:1.7.0'
157 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
158 | implementation 'com.google.android.material:material:1.6.1'
159 |
160 | implementation "androidx.tracing:tracing:1.1.0"
161 | testImplementation 'junit:junit:4.13.2'
162 | androidTestImplementation "androidx.test.ext:junit-ktx:$extJUnitVersion"
163 | androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
164 | androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.3.0'
165 | androidTestImplementation "androidx.test:rules:$androidXTestVersion"
166 | androidTestUtil "androidx.test.services:test-services:$servicesVersion"
167 |
168 | gvrImplementation 'com.google.vr:sdk-base:1.200.0@aar'
169 | implementation 'com.google.cardboard.sdk:cardboard-sdk:1.17.0@aar'
170 | implementation 'io.github.zxing-cpp:android:2.3.0-SNAPSHOT'
171 | implementation 'com.google.protobuf:protobuf-javalite:3.19.4'
172 | implementation 'androidx.camera:camera-core:1.3.4'
173 | implementation 'androidx.camera:camera-view:1.3.4'
174 | implementation 'androidx.camera:camera-lifecycle:1.3.4'
175 | implementation 'androidx.camera:camera-camera2:1.3.4'
176 |
177 | def acraVersion = '5.7.0'
178 | implementation "ch.acra:acra-mail:$acraVersion"
179 | implementation "ch.acra:acra-dialog:$acraVersion"
180 |
181 | implementation platform('com.google.firebase:firebase-bom:26.0.0')
182 | implementation 'com.google.firebase:firebase-analytics-ktx'
183 | }
184 |
185 | // The dependencies for NDK builds live inside the .aar files so they need to
186 | // be extracted before NDK targets can link against.
187 | task extractNdk(type: Copy) {
188 | copy {
189 | from zipTree("../cardboard/cardboard-sdk.aar")
190 | into "libraries/"
191 | include "jni/**/libGfxPluginCardboard.so"
192 | }
193 | if (file("../gvr-android-sdk-1.200/libraries/sdk-base-1.200.0.aar").exists()) {
194 | copy {
195 | from zipTree("../gvr-android-sdk-1.200/libraries/sdk-base-1.200.0.aar")
196 | into "libraries_gvr/"
197 | include "headers/vr/gvr/capi/**/*h"
198 | include "jni/**/libgvr_audio.so"
199 | include "jni/**/libgvr.so"
200 | }
201 | }
202 | }
203 |
204 | task deleteNdk(type: Delete) {
205 | delete "libraries/"
206 | delete "../ALVR/build/"
207 | delete "../ALVR/target/"
208 | }
209 |
210 | task buildClientLib {
211 | doLast {
212 | exec {
213 | workingDir '../ALVR'
214 | if(defaultALVRFlavour.length() > 0)
215 | commandLine 'cargo', 'xtask', 'build-client-lib', '--no-stdcpp', defaultALVRFlavour
216 | else
217 | commandLine 'cargo', 'xtask', 'build-client-lib', '--no-stdcpp'
218 | }
219 | }
220 | }
221 |
222 | // run /src/androidTest/java/viritualisres/phonevr/utils/pvr-adb-telnet.sh before starting connectedAndroidTest
223 | // TODO: Automate with gradle tasks
224 | //connectedAndroidTest.dependsOn(runPVRADBTelnetServer)
225 |
226 | spotless {
227 | java {
228 | // don't need to set target, it is inferred from java
229 | // fix formatting of type annotations
230 | target '**/*.java'
231 | formatAnnotations()
232 | removeUnusedImports()
233 | // apply a specific flavor of google-java-format
234 | googleJavaFormat().aosp().reflowLongStrings()
235 | // make sure every file has the following copyright header.
236 | // optionally, Spotless can set copyright years by digging
237 | // through git history (see "license" section below)
238 | licenseHeader '/* (C)$YEAR */'
239 | }
240 | kotlin {
241 | // by default the target is every '.kt' and '.kts` file in the java sourcesets
242 | target '**/*.kt'
243 | ktfmt().dropboxStyle() // has its own section below
244 | licenseHeader '/* (C)$YEAR */' // or licenseHeaderFile
245 | }
246 | }
247 |
248 | preBuild.dependsOn(buildClientLib)
249 | preBuild.dependsOn("spotlessCheck")
250 |
251 | build.dependsOn(extractNdk)
252 | build.dependsOn(buildClientLib)
253 |
254 | clean.dependsOn(deleteNdk)
255 |
--------------------------------------------------------------------------------
/code/mobile/mobile-common/PVRRenderer.cpp:
--------------------------------------------------------------------------------
1 | #include "PVRRenderer.h"
2 |
3 | #include "Geometry"
4 | #include
5 |
6 | #include "PVRSockets.h"
7 | #include "Utils/RenderUtils.h"
8 |
9 | using namespace std;
10 | using namespace gvr;
11 | using namespace Eigen;
12 |
13 | // globals
14 |
15 | namespace PVR {
16 | unique_ptr gvrApi;
17 | }
18 |
19 | using namespace PVR;
20 |
21 | namespace {
22 |
23 | bool reproj = false;
24 | bool debugMode = false;
25 | float offFov;
26 |
27 | gvr_context *gvrCtx; // only for ios
28 | unique_ptr swapChain;
29 | unique_ptr vps;
30 |
31 | Matrix4f rotInv = Matrix4f::Identity();
32 | unique_ptr videoRdr[2];
33 |
34 | Matrix4f gvrToEigenMat(Mat4f gvrMat) {
35 | Matrix4f eMat;
36 | try {
37 | for (int i = 0; i < 4; ++i) {
38 | for (int j = 0; j < 4; ++j) {
39 | eMat(i, j) = gvrMat.m[i][j];
40 | }
41 | }
42 | } catch (exception e) {
43 | PVR_DB_I("PVRRenderer_gvrToEigenMat:: Caught Exception: " + string(e.what()));
44 | }
45 | return eMat;
46 | }
47 |
48 | const float deg2rad = (float) M_PI / 180;
49 | const float nearP = 0.1;
50 | const float farP = 10;
51 |
52 | Matrix4f Perspective(const Rectf &fov) {
53 | Matrix4f res;
54 | try {
55 | res = Matrix4f::Zero();
56 | float left = -tan(fov.left * deg2rad) * nearP;
57 | float top = tan(fov.top * deg2rad) * nearP;
58 | float right = tan(fov.right * deg2rad) * nearP;
59 | float bottom = -tan(fov.bottom * deg2rad) * nearP;
60 |
61 | res(0, 0) = (2 * nearP) / (right - left);
62 | res(0, 2) = (right + left) / (right - left);
63 | res(1, 1) = (2 * nearP) / (top - bottom);
64 | res(1, 2) = (top + bottom) / (top - bottom);
65 | res(2, 2) = (nearP + farP) / (nearP - farP);
66 | res(2, 3) = (2 * nearP * farP) / (nearP - farP);
67 | res(3, 2) = -1;
68 | } catch (exception e) {
69 | PVR_DB_I("PVRRenderer_Perspectivet:: Caught Exception: " + string(e.what()));
70 | }
71 |
72 | return res;
73 | }
74 |
75 | struct EyeData {
76 | int vpLeft, vpBottom, vpWidth, vpHeight;
77 | Matrix4f quadModel, proj;
78 | } eyes[2];
79 |
80 | vector leftQuad;
81 |
82 | void InitGVRRendering() {
83 | try {
84 | if (gvrApi) {
85 | gvrApi->RefreshViewerProfile();
86 |
87 | vector specs;
88 | specs.push_back(gvrApi->CreateBufferSpec());
89 | int rdrWidth = specs[0].GetSize().width;
90 | int rdrHeight = specs[0].GetSize().height;
91 | swapChain.reset(new SwapChain(gvrApi->CreateSwapChain(specs)));
92 | vps.reset(new BufferViewportList(gvrApi->CreateEmptyBufferViewportList()));
93 | vps->SetToRecommendedBufferViewports();
94 |
95 | for (size_t i = 0; i < 2; ++i) {
96 | EyeData e;
97 | auto bufVp = gvrApi->CreateBufferViewport();
98 | vps->GetBufferViewport(i, &bufVp);
99 |
100 | auto rect = bufVp.GetSourceUv();
101 | e.vpLeft = int(rect.left * rdrWidth);
102 | e.vpBottom = int(rect.bottom * rdrHeight);
103 | e.vpWidth = int((rect.right - rect.left) * rdrWidth);
104 | e.vpHeight = int((rect.top - rect.bottom) * rdrHeight);
105 |
106 | auto fov = bufVp.GetSourceFov();
107 | e.proj = Perspective(fov);
108 |
109 | Rectf quad;
110 | quad.left = -tan((fov.left + offFov) * deg2rad);
111 | quad.top =
112 | tan((fov.top + offFov * 2 / 3) * deg2rad); // augment less vertical fov
113 | quad.right = tan((fov.right + offFov) * deg2rad);
114 | quad.bottom = -tan((fov.bottom + offFov * 2 / 3) * deg2rad);
115 | if (i == GVR_LEFT_EYE) {
116 | leftQuad = {quad.left, quad.top, quad.right, quad.bottom};
117 | }
118 | e.quadModel = Affine3f(Translation3f((quad.right + quad.left) / 2.f,
119 | (quad.top + quad.bottom) / 2.f,
120 | -1.f))
121 | .matrix() *
122 | Affine3f(Scaling((quad.right - quad.left) / 2.f,
123 | (quad.top - quad.bottom) / 2.f,
124 | 1.f))
125 | .matrix();
126 |
127 | eyes[i] = e;
128 | }
129 | }
130 | } catch (exception e) {
131 | PVR_DB_I("PVRRenderer_InitGVRRendering:: Caught Exception: " + string(e.what()));
132 | }
133 | }
134 |
135 | // Matrix4f eyeMat = gvrToEigenMat(gvrApi->GetEyeFromHeadMatrix(eye)) * headMat;
136 | // lastRotMatInv = headMat.inverse();
137 | } // namespace
138 |
139 | unsigned int PVRInitSystem(int maxW, int maxH, float offFov, bool reproj, bool debug) {
140 |
141 | unsigned int videoTex;
142 | try {
143 | pvrState = PVR_STATE_INITIALIZATION;
144 | gvrApi->InitializeGl();
145 | // auto fjdkl = gvrApi->IsFeatureSupported(GVR_FEATURE_MULTIVIEW);
146 |
147 | ::offFov = offFov;
148 | ::reproj = reproj;
149 | debugMode = debug;
150 |
151 | InitGVRRendering();
152 |
153 | // block until receive nal headers. todo: optimize timing
154 | SendAdditionalData({(uint16_t) maxW, (uint16_t) maxH},
155 | leftQuad,
156 | gvrApi->GetEyeFromHeadMatrix(GVR_LEFT_EYE).m[0][3] *
157 | 2); // extracting IPD
158 |
159 | videoTex = genTexture(true);
160 | videoRdr[0].reset(new Renderer({{videoTex, true}}, FS_PT, 0.0f, 0.5f));
161 | videoRdr[1].reset(new Renderer({{videoTex, true}}, FS_PT, 0.5f, 1.0f));
162 |
163 | gvrApi->ResumeTracking();
164 | } catch (exception e) {
165 | PVR_DB_I("PVRRenderer_InitGVRRendering:: Caught Exception: " + string(e.what()));
166 | }
167 |
168 | return videoTex;
169 | }
170 |
171 | void PVRRender(int64_t pts) {
172 | try {
173 | PVR_DB("PVRRender:: Rendering " + to_string(pts));
174 | if (pvrState == PVR_STATE_RUNNING) {
175 | static Clk::time_point oldtime = Clk::now();
176 |
177 | if (pts > 0) {
178 | vector v = DequeueQuatAtPts(pts);
179 | if (v.size() == 4)
180 | rotInv.block(0, 0, 3, 3) =
181 | Matrix3f(Quaternionf(v[0], v[1], v[2], v[3])); // todo: simplify
182 | // rotInv = rotMat;//.inverse(); ?
183 | }
184 |
185 | // vps->SetToRecommendedBufferViewports();
186 | Frame frame = swapChain->AcquireFrame();
187 |
188 | frame.BindBuffer(0);
189 | if (!debugMode)
190 | glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // black background
191 | else
192 | glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // red background
193 | glEnable(GL_DEPTH_TEST);
194 | glEnable(GL_SCISSOR_TEST);
195 |
196 | ClockTimePoint tgt_time = GvrApi::GetTimePointNow();
197 | tgt_time.monotonic_system_time_nanos += 20000000; // 0.020 s
198 | Mat4f gvrHeadMat = gvrApi->GetHeadSpaceFromStartSpaceRotation(tgt_time);
199 | Matrix4f deltaRot = gvrToEigenMat(gvrHeadMat) * rotInv;
200 |
201 | for (int i = 0; i < 2; ++i) {
202 | auto e = eyes[i];
203 | glViewport(e.vpLeft, e.vpBottom, e.vpWidth, e.vpHeight);
204 | glScissor(e.vpLeft, e.vpBottom, e.vpWidth, e.vpHeight);
205 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
206 |
207 | Matrix4f mvp;
208 | if (reproj)
209 | mvp = e.proj * deltaRot * e.quadModel; // order sensitive!!
210 | else
211 | mvp = e.proj * e.quadModel;
212 |
213 | videoRdr[i]->render(mvp);
214 | }
215 |
216 | frame.Unbind();
217 | frame.Submit(*vps, gvrHeadMat);
218 |
219 | fpsRenderer = (1000000000.0 / (Clk::now() - oldtime).count());
220 | oldtime = Clk::now();
221 | }
222 | } catch (exception e) {
223 | PVR_DB_I("PVRRenderer_PVRRender:: Caught Exception: " + string(e.what()));
224 | }
225 | }
226 |
227 | void PVRTrigger() {} // TODO: register press
228 |
229 | void PVRPause() {
230 | try {
231 | if (pvrState == PVR_STATE_RUNNING && gvrApi) {
232 | gvrApi->PauseTracking();
233 | pvrState = PVR_STATE_PAUSED;
234 | }
235 | } catch (exception e) {
236 | PVR_DB_I("PVRRenderer_PVRPause:: Caught Exception: " + string(e.what()));
237 | }
238 | }
239 |
240 | void PVRResume() {
241 | try {
242 | if (pvrState == PVR_STATE_PAUSED && gvrApi) {
243 | InitGVRRendering();
244 | gvrApi->ResumeTracking();
245 | pvrState = PVR_STATE_RUNNING;
246 | }
247 | } catch (exception e) {
248 | PVR_DB_I("PVRRenderer_PVRResume:: Caught Exception: " + string(e.what()));
249 | }
250 | }
251 |
252 | void PVRCreateGVR(gvr_context *ctx) {
253 | try {
254 | gvrApi = GvrApi::WrapNonOwned(ctx);
255 | } catch (exception e) {
256 | PVR_DB_I("PVRRenderer_PVRCreateGVR:: Caught Exception: " + string(e.what()));
257 | }
258 | }
259 |
260 | void PVRDestroyGVR() {
261 | try {
262 | gvr_destroy(&gvrCtx);
263 | } catch (exception e) {
264 | PVR_DB_I("PVRRenderer_PVRDestroyGVR:: Caught Exception: " + string(e.what()));
265 | }
266 | }
267 |
268 | #ifdef __APPLE__
269 |
270 | void PVRCreateGVRAndContext() {
271 | gvrCtx = gvr_create();
272 | PVRCreateGVR(gvrCtx);
273 | }
274 | #endif
275 |
--------------------------------------------------------------------------------
/code/mobile/android/PhoneVR/app/src/main/java/viritualisres/phonevr/DiscordReportSender.java:
--------------------------------------------------------------------------------
1 | /* (C)2023 */
2 | package viritualisres.phonevr;
3 |
4 | import android.content.Context;
5 | import android.os.AsyncTask;
6 | import android.util.Log;
7 | import java.io.BufferedOutputStream;
8 | import java.io.BufferedWriter;
9 | import java.io.OutputStream;
10 | import java.io.OutputStreamWriter;
11 | import java.net.HttpURLConnection;
12 | import java.net.URL;
13 | import java.nio.charset.StandardCharsets;
14 | import java.util.Objects;
15 | import java.util.UUID;
16 | import java.util.regex.Matcher;
17 | import java.util.regex.Pattern;
18 | import org.acra.data.CrashReportData;
19 | import org.acra.sender.ReportSender;
20 | import org.acra.util.BundleWrapper;
21 | import org.jetbrains.annotations.NotNull;
22 | import org.json.JSONArray;
23 | import org.json.JSONException;
24 | import org.json.JSONObject;
25 |
26 | public class DiscordReportSender implements ReportSender {
27 |
28 | @Override
29 | public void send(
30 | @NotNull Context context,
31 | @NotNull CrashReportData report,
32 | @NotNull BundleWrapper extras) {
33 | try {
34 | // Log.d("ACRA-PVR", "Waiting for debugger to Attach !");
35 | // android.os.Debug.waitForDebugger();
36 | // Log.d("ACRA-PVR", "Debugger Attached XD");
37 | PostDiscord send = new PostDiscord(report);
38 | send.doInBackground();
39 | Log.d("ACRA-PVR", "Called Send3");
40 |
41 | } catch (JSONException e) {
42 | Log.d("ACRA-PVR", "Caught Exception : " + e.getMessage());
43 | e.printStackTrace();
44 | }
45 | }
46 |
47 | public static class PostDiscord extends AsyncTask {
48 |
49 | String FileData, ExceptionMsg;
50 | CrashReportData reportsData;
51 |
52 | public PostDiscord(CrashReportData report) throws JSONException {
53 |
54 | FileData = report.toJSON().toString();
55 | ExceptionMsg = Objects.requireNonNull(report.toMap().get("STACK_TRACE")).toString();
56 | ExceptionMsg = ExceptionMsg.substring(0, ExceptionMsg.indexOf("\n"));
57 | reportsData = report;
58 | }
59 |
60 | @Override
61 | protected void onPreExecute() {
62 | super.onPreExecute();
63 | }
64 |
65 | @Override
66 | protected Void doInBackground(String... params) {
67 | try {
68 |
69 | // String urlString =
70 | // "https://discord.com/api/webhooks/772915848775991310/teIX_7vPM30wrx5bjs1iFsHPBIL-twth6iPH1cd5VW5W2goxr50SmPT3l3O4X7iB9bSG"; // URL to call
71 | String urlString =
72 | "https://discord.com/api/webhooks/1095611501554958356/oIAVJopxxG0i_MAAjwOS0FwV4_ycIG3709gs4zIlCpyLpCNcbBCGiB1mo7B1qCB_uk7z"; // URL to call
73 | URL url = new URL(urlString);
74 | String boundary = UUID.randomUUID().toString();
75 | HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
76 |
77 | urlConnection.setRequestMethod("POST");
78 | urlConnection.setRequestProperty(
79 | "Content-Type", "multipart/form-data; boundary=" + boundary);
80 | urlConnection.setDoOutput(true);
81 |
82 | OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
83 | BufferedWriter writer =
84 | new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
85 |
86 | int firstLetter =
87 | Character.codePointAt(
88 | ((JSONObject) reportsData.get("INITIAL_CONFIGURATION"))
89 | .get("locale")
90 | .toString(),
91 | 3)
92 | - 0x41
93 | + 0x1F1E6;
94 | int secondLetter =
95 | Character.codePointAt(
96 | ((JSONObject) reportsData.get("INITIAL_CONFIGURATION"))
97 | .get("locale")
98 | .toString(),
99 | 4)
100 | - 0x41
101 | + 0x1F1E6;
102 |
103 | String gitFileUrl =
104 | "https://github.com/PhoneVR-Developers/PhoneVR/blob/master/code/mobile/android/PhoneVR/app/src/main/java/viritualisres/phonevr/";
105 |
106 | Pattern p =
107 | Pattern.compile(
108 | "(viritualisres\\.phonevr[^{}():\\n\\t]*?\\(.*?:[0-9]*?\\).*?)\\n");
109 | Matcher m = p.matcher(reportsData.get("STACK_TRACE").toString());
110 | StringBuilder pvrRelatedFiles = new StringBuilder();
111 |
112 | while (m.find()) {
113 | pvrRelatedFiles.append(
114 | " --> "
115 | + m.group(0)
116 | .replaceAll("\n|\t", "")
117 | .replaceAll(
118 | "\\((.*?):([0-9]*?)\\).*?",
119 | "([$1:$2](" + gitFileUrl + "$1#L$2))")
120 | + "\n");
121 | }
122 | JSONObject JsonPayload = new JSONObject();
123 |
124 | JsonPayload.put(
125 | "embeds",
126 | new JSONArray()
127 | .put(
128 | new JSONObject()
129 | .put(
130 | "author",
131 | new JSONObject()
132 | .put("name", "Github CrossRef")
133 | .put(
134 | "url",
135 | "https://github.com/ShootingKing-AM")
136 | .put(
137 | "icon_url",
138 | "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"))
139 | .put(
140 | "footer",
141 | new JSONObject()
142 | .put(
143 | "icon_url",
144 | "https://avatars0.githubusercontent.com/u/4137788?s=100")
145 | .put("text", "ShootinKing-AM"))
146 | .put("color", 16760388)
147 | .put("title", "Stack trace")
148 | .put("description", pvrRelatedFiles)));
149 |
150 | JsonPayload.put(
151 | "content",
152 | "An `"
153 | + ((JSONObject) reportsData.get("BUILD")).getString("MANUFACTURER")
154 | + " "
155 | + ((JSONObject) reportsData.get("BUILD")).get("MODEL")
156 | + " Android v"
157 | + reportsData.get("ANDROID_VERSION")
158 | + "("
159 | + ((JSONObject) reportsData.get("INITIAL_CONFIGURATION"))
160 | .get("locale")
161 | + ") `"
162 | + (new String(Character.toChars(firstLetter))
163 | + new String(Character.toChars(secondLetter)))
164 | + " crashed on ```css\n"
165 | + "Time: "
166 | + reportsData.get("USER_CRASH_DATE")
167 | + "\n"
168 | + "App Version: "
169 | + ((JSONObject) reportsData.get("BUILD_CONFIG")).get("VERSION_NAME")
170 | + "_"
171 | + ((JSONObject) reportsData.get("BUILD_CONFIG")).get("VERSION_CODE")
172 | + "```*With:*\n```ml\n"
173 | + ExceptionMsg
174 | + "```\n");
175 |
176 | writer.write("--" + boundary + "\r\n");
177 | writer.write(
178 | "Content-Disposition: form-data; name=\"file\";"
179 | + " filename=\"pvrcrash.stacktrace\" \r\n\r\n");
180 | writer.write(FileData + "\r\n");
181 | writer.write("--" + boundary + "\r\n");
182 |
183 | writer.write("Content-Disposition: form-data; name=\"payload_json\"\r\n\r\n");
184 | writer.write(JsonPayload.toString() + "\r\n");
185 | writer.write("--" + boundary + "--\r\n");
186 |
187 | writer.flush();
188 | writer.close();
189 | out.close();
190 |
191 | urlConnection.connect();
192 | Log.d(
193 | "ACRA-PVR",
194 | "Connection Resp Code : "
195 | + urlConnection.getResponseCode()
196 | + "; Resp Msg : "
197 | + urlConnection.getResponseMessage());
198 | urlConnection.getInputStream().close();
199 | urlConnection.disconnect();
200 |
201 | } catch (Exception e) {
202 | Log.d("ACRA-PVR", "Exception Caught : " + e.getMessage());
203 | e.printStackTrace();
204 | }
205 | return null;
206 | }
207 | }
208 | }
209 |
--------------------------------------------------------------------------------