Change internal name dist -> disk.
[dcpomatic.git] / src / lib / cross_osx.cc
1 /*
2     Copyright (C) 2012-2020 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "cross.h"
22 #include "compose.hpp"
23 #include "log.h"
24 #include "dcpomatic_log.h"
25 #include "config.h"
26 #include "exceptions.h"
27 #include <dcp/raw_convert.h>
28 #include <glib.h>
29 extern "C" {
30 #include <libavformat/avio.h>
31 }
32 #include <boost/algorithm/string.hpp>
33 #include <boost/foreach.hpp>
34 #include <boost/dll/runtime_symbol_info.hpp>
35 #include <sys/sysctl.h>
36 #include <mach-o/dyld.h>
37 #include <IOKit/pwr_mgt/IOPMLib.h>
38 #include <DiskArbitration/DADisk.h>
39 #include <DiskArbitration/DiskArbitration.h>
40 #include <sys/types.h>
41 #include <ifaddrs.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <fstream>
45
46 #include "i18n.h"
47
48 using std::pair;
49 using std::list;
50 using std::ifstream;
51 using std::string;
52 using std::wstring;
53 using std::make_pair;
54 using std::vector;
55 using std::cerr;
56 using std::cout;
57 using std::runtime_error;
58 using boost::shared_ptr;
59 using boost::optional;
60
61 /** @param s Number of seconds to sleep for */
62 void
63 dcpomatic_sleep_seconds (int s)
64 {
65         sleep (s);
66 }
67
68 void
69 dcpomatic_sleep_milliseconds (int ms)
70 {
71         usleep (ms * 1000);
72 }
73
74 /** @return A string of CPU information (model name etc.) */
75 string
76 cpu_info ()
77 {
78         string info;
79
80         char buffer[64];
81         size_t N = sizeof (buffer);
82         if (sysctlbyname ("machdep.cpu.brand_string", buffer, &N, 0, 0) == 0) {
83                 info = buffer;
84         }
85
86         return info;
87 }
88
89 /** @return Path of the Contents directory in the .app */
90 boost::filesystem::path
91 app_contents ()
92 {
93         return boost::dll::program_location().parent_path().parent_path();
94 }
95
96 boost::filesystem::path
97 shared_path ()
98 {
99         return app_contents() / "Resources";
100 }
101
102 void
103 run_ffprobe (boost::filesystem::path content, boost::filesystem::path out)
104 {
105         boost::filesystem::path path = app_contents();
106         path /= "MacOS";
107         path /= "ffprobe";
108
109         string ffprobe = "\"" + path.string() + "\" \"" + content.string() + "\" 2> \"" + out.string() + "\"";
110         LOG_GENERAL (N_("Probing with %1"), ffprobe);
111         system (ffprobe.c_str ());
112 }
113
114 list<pair<string, string> >
115 mount_info ()
116 {
117         list<pair<string, string> > m;
118         return m;
119 }
120
121 boost::filesystem::path
122 openssl_path ()
123 {
124         boost::filesystem::path path = app_contents();
125         path /= "MacOS";
126         path /= "openssl";
127         return path;
128 }
129
130 boost::filesystem::path
131 disk_writer_path ()
132 {
133         boost::filesystem::path path = app_contents();
134         path /= "MacOS";
135         path /= "dcpomatic2_disk_writer";
136         return path;
137 }
138
139 /* Apparently there is no way to create an ofstream using a UTF-8
140    filename under Windows.  We are hence reduced to using fopen
141    with this wrapper.
142 */
143 FILE *
144 fopen_boost (boost::filesystem::path p, string t)
145 {
146         return fopen (p.c_str(), t.c_str ());
147 }
148
149 int
150 dcpomatic_fseek (FILE* stream, int64_t offset, int whence)
151 {
152         return fseek (stream, offset, whence);
153 }
154
155 void
156 Waker::nudge ()
157 {
158
159 }
160
161 Waker::Waker ()
162 {
163         boost::mutex::scoped_lock lm (_mutex);
164         /* We should use this */
165         // IOPMAssertionCreateWithName (kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, CFSTR ("Encoding DCP"), &_assertion_id);
166         /* but it's not available on 10.5, so we use this */
167         IOPMAssertionCreate (kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, &_assertion_id);
168 }
169
170 Waker::~Waker ()
171 {
172         boost::mutex::scoped_lock lm (_mutex);
173         IOPMAssertionRelease (_assertion_id);
174 }
175
176 void
177 start_tool (boost::filesystem::path dcpomatic, string executable, string app)
178 {
179         boost::filesystem::path batch = dcpomatic.parent_path ();
180         batch = batch.parent_path (); // MacOS
181         batch = batch.parent_path (); // Contents
182         batch = batch.parent_path (); // DCP-o-matic.app
183         batch = batch.parent_path (); // Applications
184         batch /= app;
185         batch /= "Contents";
186         batch /= "MacOS";
187         batch /= executable;
188
189         pid_t pid = fork ();
190         if (pid == 0) {
191                 int const r = system (batch.string().c_str());
192                 exit (WEXITSTATUS (r));
193         }
194 }
195
196 void
197 start_batch_converter (boost::filesystem::path dcpomatic)
198 {
199         start_tool (dcpomatic, "dcpomatic2_batch", "DCP-o-matic\\ 2\\ Batch\\ Converter.app");
200 }
201
202 void
203 start_player (boost::filesystem::path dcpomatic)
204 {
205         start_tool (dcpomatic, "dcpomatic2_player", "DCP-o-matic\\ 2\\ Player.app");
206 }
207
208 uint64_t
209 thread_id ()
210 {
211         return (uint64_t) pthread_self ();
212 }
213
214 int
215 avio_open_boost (AVIOContext** s, boost::filesystem::path file, int flags)
216 {
217         return avio_open (s, file.c_str(), flags);
218 }
219
220 boost::filesystem::path
221 home_directory ()
222 {
223                 return getenv("HOME");
224 }
225
226 string
227 command_and_read (string cmd)
228 {
229         return "";
230 }
231
232 /** @return true if this process is a 32-bit one running on a 64-bit-capable OS */
233 bool
234 running_32_on_64 ()
235 {
236         /* I'm assuming nobody does this on OS X */
237         return false;
238 }
239
240 static void
241 disk_appeared(DADiskRef disk, void* context)
242 {
243         const char* name = DADiskGetBSDName (disk);
244         if (name) {
245                 list<Drive>* drives = reinterpret_cast<list<Drive>*> (context);
246                 drives->push_back (Drive(name, 0, false, optional<string>(), optional<string>()));
247         }
248 }
249
250 vector<Drive>
251 get_drives ()
252 {
253         vector<Drive> drives;
254
255         DASessionRef session = DASessionCreate(kCFAllocatorDefault);
256         if (!session) {
257                 return drives;
258         }
259
260         DARegisterDiskAppearedCallback (session, NULL, disk_appeared, &drives);
261         CFRunLoopRef run_loop = CFRunLoopGetCurrent ();
262         DASessionScheduleWithRunLoop (session, run_loop, kCFRunLoopDefaultMode);
263         CFRunLoopStop (run_loop);
264         CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.05, 0);
265         DAUnregisterCallback(session, (void *) disk_appeared, &drives);
266         CFRelease(session);
267
268         return drives;
269 }
270
271 string
272 Drive::description () const
273 {
274         char gb[64];
275         snprintf(gb, 64, "%.1f", _size / 1000000000.0);
276
277         string name;
278         if (_vendor) {
279                 name += *_vendor;
280         }
281         if (_model) {
282                 if (name.size() > 0) {
283                         name += " " + *_model;
284                 }
285         }
286         if (name.size() == 0) {
287                 name = _("Unknown");
288         }
289
290         return String::compose("%1 (%2 GB) [%3]", name, gb, _internal_name);
291 }
292
293 boost::filesystem::path
294 config_path ()
295 {
296         boost::filesystem::path p;
297         p /= g_get_home_dir ();
298         p /= "Library";
299         p /= "Preferences";
300         p /= "com.dcpomatic";
301         p /= "2";
302         return p;
303 }