Debug to check boost::dll.
[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         std::cout << "program_location=" << boost::dll::program_location() << "\n";
94         return boost::dll::program_location().parent_path().parent_path();
95 }
96
97 boost::filesystem::path
98 shared_path ()
99 {
100         return app_contents() / "Resources";
101 }
102
103 void
104 run_ffprobe (boost::filesystem::path content, boost::filesystem::path out)
105 {
106         boost::filesystem::path path = app_contents();
107         path /= "MacOS";
108         path /= "ffprobe";
109
110         string ffprobe = "\"" + path.string() + "\" \"" + content.string() + "\" 2> \"" + out.string() + "\"";
111         LOG_GENERAL (N_("Probing with %1"), ffprobe);
112         system (ffprobe.c_str ());
113 }
114
115 list<pair<string, string> >
116 mount_info ()
117 {
118         list<pair<string, string> > m;
119         return m;
120 }
121
122 boost::filesystem::path
123 openssl_path ()
124 {
125         boost::filesystem::path path = app_contents();
126         path /= "MacOS";
127         path /= "openssl";
128         return path;
129 }
130
131 boost::filesystem::path
132 disk_writer_path ()
133 {
134         boost::filesystem::path path = app_contents();
135         path /= "MacOS";
136         path /= "dcpomatic2_disk_writer";
137         return path;
138 }
139
140 /* Apparently there is no way to create an ofstream using a UTF-8
141    filename under Windows.  We are hence reduced to using fopen
142    with this wrapper.
143 */
144 FILE *
145 fopen_boost (boost::filesystem::path p, string t)
146 {
147         return fopen (p.c_str(), t.c_str ());
148 }
149
150 int
151 dcpomatic_fseek (FILE* stream, int64_t offset, int whence)
152 {
153         return fseek (stream, offset, whence);
154 }
155
156 void
157 Waker::nudge ()
158 {
159
160 }
161
162 Waker::Waker ()
163 {
164         boost::mutex::scoped_lock lm (_mutex);
165         /* We should use this */
166         // IOPMAssertionCreateWithName (kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, CFSTR ("Encoding DCP"), &_assertion_id);
167         /* but it's not available on 10.5, so we use this */
168         IOPMAssertionCreate (kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, &_assertion_id);
169 }
170
171 Waker::~Waker ()
172 {
173         boost::mutex::scoped_lock lm (_mutex);
174         IOPMAssertionRelease (_assertion_id);
175 }
176
177 void
178 start_tool (boost::filesystem::path dcpomatic, string executable, string app)
179 {
180         boost::filesystem::path batch = dcpomatic.parent_path ();
181         batch = batch.parent_path (); // MacOS
182         batch = batch.parent_path (); // Contents
183         batch = batch.parent_path (); // DCP-o-matic.app
184         batch = batch.parent_path (); // Applications
185         batch /= app;
186         batch /= "Contents";
187         batch /= "MacOS";
188         batch /= executable;
189
190         pid_t pid = fork ();
191         if (pid == 0) {
192                 int const r = system (batch.string().c_str());
193                 exit (WEXITSTATUS (r));
194         }
195 }
196
197 void
198 start_batch_converter (boost::filesystem::path dcpomatic)
199 {
200         start_tool (dcpomatic, "dcpomatic2_batch", "DCP-o-matic\\ 2\\ Batch\\ Converter.app");
201 }
202
203 void
204 start_player (boost::filesystem::path dcpomatic)
205 {
206         start_tool (dcpomatic, "dcpomatic2_player", "DCP-o-matic\\ 2\\ Player.app");
207 }
208
209 uint64_t
210 thread_id ()
211 {
212         return (uint64_t) pthread_self ();
213 }
214
215 int
216 avio_open_boost (AVIOContext** s, boost::filesystem::path file, int flags)
217 {
218         return avio_open (s, file.c_str(), flags);
219 }
220
221 boost::filesystem::path
222 home_directory ()
223 {
224                 return getenv("HOME");
225 }
226
227 string
228 command_and_read (string cmd)
229 {
230         return "";
231 }
232
233 /** @return true if this process is a 32-bit one running on a 64-bit-capable OS */
234 bool
235 running_32_on_64 ()
236 {
237         /* I'm assuming nobody does this on OS X */
238         return false;
239 }
240
241 static void
242 disk_appeared(DADiskRef disk, void* context)
243 {
244         const char* name = DADiskGetBSDName (disk);
245         if (name) {
246                 list<Drive>* drives = reinterpret_cast<list<Drive>*> (context);
247                 drives->push_back (Drive(name, 0, false, optional<string>(), optional<string>()));
248         }
249 }
250
251 vector<Drive>
252 get_drives ()
253 {
254         vector<Drive> drives;
255
256         DASessionRef session = DASessionCreate(kCFAllocatorDefault);
257         if (!session) {
258                 return drives;
259         }
260
261         DARegisterDiskAppearedCallback (session, NULL, disk_appeared, &drives);
262         CFRunLoopRef run_loop = CFRunLoopGetCurrent ();
263         DASessionScheduleWithRunLoop (session, run_loop, kCFRunLoopDefaultMode);
264         CFRunLoopStop (run_loop);
265         CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.05, 0);
266         DAUnregisterCallback(session, (void *) disk_appeared, &drives);
267         CFRelease(session);
268
269         return drives;
270 }
271
272 string
273 Drive::description () const
274 {
275         char gb[64];
276         snprintf(gb, 64, "%.1f", _size / 1000000000.0);
277
278         string name;
279         if (_vendor) {
280                 name += *_vendor;
281         }
282         if (_model) {
283                 if (name.size() > 0) {
284                         name += " " + *_model;
285                 }
286         }
287         if (name.size() == 0) {
288                 name = _("Unknown");
289         }
290
291         return String::compose("%1 (%2 GB) [%3]", name, gb, _internal_name);
292 }
293
294 boost::filesystem::path
295 config_path ()
296 {
297         boost::filesystem::path p;
298         p /= g_get_home_dir ();
299         p /= "Library";
300         p /= "Preferences";
301         p /= "com.dcpomatic";
302         p /= "2";
303         return p;
304 }