From e18f8a7b09aabd470e9925572c4432732ef366d9 Mon Sep 17 00:00:00 2001 From: Julien Wadel <julien.wadel@belledonne-communications.com> Date: Thu, 20 May 2021 10:43:03 +0200 Subject: [PATCH] Fix daemon and tester on performing stuff on Main thread (like video displaying) - Override main() to instantiate a Main Loop. - Add Info.plist to liblinphonetester to get video permissions if needed --- build/osx/Info.plist.in | 4 +- daemon/CMakeLists.txt | 7 +- daemon/daemon.cc | 5 +- src/utils/main-loop-integration-macos.m | 113 ++++++++++++++++++++++++ tester/CMakeLists.txt | 6 +- tester/call_video_tester.cpp | 4 + tester/liblinphone_tester.c | 10 +-- tester/liblinphone_tester.h | 2 - 8 files changed, 140 insertions(+), 11 deletions(-) create mode 100644 src/utils/main-loop-integration-macos.m diff --git a/build/osx/Info.plist.in b/build/osx/Info.plist.in index 599faf2197..7bd2d43774 100644 --- a/build/osx/Info.plist.in +++ b/build/osx/Info.plist.in @@ -39,5 +39,7 @@ <string>NSApplication</string> <key>NSHighResolutionCapable</key> <string>True</string> + <key>NSCameraUsageDescription</key> + <string>Allow camera for video sessions</string> </dict> -</plist> \ No newline at end of file +</plist> diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index dba1788e7d..544d93f59b 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -113,10 +113,15 @@ set(DAEMON_SOURCE_FILES set(DAEMON_PIPETEST_SOURCE_FILES daemon-pipetest.c ) +set(DAEMON_SOURCE_FILES_OBJC ) +if(APPLE) + list(APPEND DAEMON_SOURCE_FILES_OBJC ../src/utils/main-loop-integration-macos.m) +endif() bc_apply_compile_flags(DAEMON_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_CXX) bc_apply_compile_flags(DAEMON_PIPETEST_SOURCE_FILES STRICT_OPTIONS_CPP STRICT_OPTIONS_C) -add_executable(linphone-daemon ${DAEMON_SOURCE_FILES}) +bc_apply_compile_flags(DAEMON_SOURCE_FILES_OBJC STRICT_OPTIONS_CPP STRICT_OPTIONS_OBJC) +add_executable(linphone-daemon ${DAEMON_SOURCE_FILES} ${DAEMON_SOURCE_FILES_OBJC}) target_include_directories(linphone-daemon PRIVATE ${CMAKE_CURRENT_LIST_DIR} ${LINPHONE_INCLUDE_DIRS}) target_link_libraries(linphone-daemon ${LINPHONE_LIBS_FOR_TOOLS} mediastreamer ortp bctoolbox ${XSD_LIBRARIES}) set_target_properties(linphone-daemon PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") diff --git a/daemon/daemon.cc b/daemon/daemon.cc index 28c6255208..3bab0bce22 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -939,8 +939,11 @@ static void sighandler(int signum){ the_app = NULL; } } - +#if defined(__APPLE__) +extern "C" int apple_main(int argc, char **argv){ +#else int main(int argc, char *argv[]) { +#endif const char *config_path = NULL; const char *factory_config_path = NULL; const char *pipe_name = NULL; diff --git a/src/utils/main-loop-integration-macos.m b/src/utils/main-loop-integration-macos.m new file mode 100644 index 0000000000..f4f71ef8df --- /dev/null +++ b/src/utils/main-loop-integration-macos.m @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2021 Belledonne Communications SARL. + * + * This file is part of Liblinphone. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Instantiate a Main Loop for Mac. + * Change your 'int main(int argc, char **argv)' by 'int apple_main(int argc, char **argv)'. + * Do not forget to use extern "C" if needed. + * + * It is currently used by : daemon and liblinphone_tester + * + */ + +#include "TargetConditionals.h" +#ifdef __APPLE__ +#import <Carbon/Carbon.h> +#import <AppKit/AppKit.h> + + +extern int apple_main(int argc, char **argv); + +@interface MyApplicationDelegate: NSObject +{ + NSWindow *window; +@public + int argc; + char **argv; + id activity; +} + + +-(void)applicationWillFinishLaunching: (NSNotification*) aNotification; +-(void)applicationDidFinishLaunching: (NSNotification*) aNotification; +-(BOOL)applicationShouldTerminateAfterLastWindowClosed: (NSApplication *)theApplication; +@end + + +@implementation MyApplicationDelegate + + + +-(void) runLoop { + exit(apple_main(argc,argv)); +} + +-(void)applicationWillFinishLaunching: (NSNotification*) aNotification +{ + if( [[NSProcessInfo processInfo] respondsToSelector:@selector(beginActivityWithOptions:reason:)] ){ + //NSActivityOptions options = NSActivityAutomaticTerminationDisabled & NSActivityIdleSystemSleepDisabled; + // NSLog(@"Disabling App nap for tester"); + self->activity = [[[NSProcessInfo processInfo] beginActivityWithOptions:0x00FFFFFF reason:@"No app nap for this tester"] retain]; + } + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{ + [self runLoop]; + }); +} + +-(void)applicationDidFinishLaunching: (NSNotification*) aNotification +{ +} + +- (void)applicationWillTerminate:(NSNotification *)aNotification { + NSLog(@"applicationWillTerminate"); + if( self->activity ){ + [[NSProcessInfo processInfo] endActivity:self->activity]; + [self->activity release]; + self->activity = nil; + } +} + +-(BOOL)applicationShouldTerminateAfterLastWindowClosed: (NSApplication *)theApplication +{ + return NO; +} + +-(void)dealloc +{ + [window release]; + [super dealloc]; +} +@end + +int main(int argc, char **argv) +{ + static const ProcessSerialNumber thePSN = { 0, kCurrentProcess }; + TransformProcessType(&thePSN, kProcessTransformToForegroundApplication); + SetFrontProcess(&thePSN); + NSAutoreleasePool *aPool = [[NSAutoreleasePool alloc] init]; + [NSApplication sharedApplication]; + MyApplicationDelegate *aMyApplicationDelegate = [[MyApplicationDelegate alloc] init]; + aMyApplicationDelegate->argc = argc; + aMyApplicationDelegate->argv = argv; + [NSApp setDelegate:(id) aMyApplicationDelegate]; + [aPool release]; + [NSApp run]; + return 0; +} +#endif diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 88a9a89072..aabe473025 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -337,6 +337,8 @@ set(SOURCE_FILES_OBJC ) if(APPLE) if (IOS) list(APPEND SOURCE_FILES_OBJC liblinphone_tester_ios.m) + else() + list(APPEND SOURCE_FILES_OBJC ../src/utils/main-loop-integration-macos.m)#Override main(), instantiate Main Loop and call apple_main() endif() endif() @@ -476,13 +478,15 @@ if(NOT ANDROID) ) endif() endif() - install(TARGETS liblinphone_tester RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE ) + if(APPLE) + configure_file("${CMAKE_SOURCE_DIR}/build/osx/Info.plist.in" "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}/Info.plist") + endif() add_executable(groupchat_benchmark ${GROUP_CHAT_BENCHMARK_HEADERS} ${GROUP_CHAT_BENCHMARK_SOURCE_C}) set_target_properties(groupchat_benchmark PROPERTIES LINK_FLAGS "${LINPHONE_LDFLAGS}") diff --git a/tester/call_video_tester.cpp b/tester/call_video_tester.cpp index 6eb63eb5ad..47b19a85ef 100644 --- a/tester/call_video_tester.cpp +++ b/tester/call_video_tester.cpp @@ -2419,12 +2419,16 @@ static test_t call_video_tests[] = { }; int init_msogl_call_suite(){ +#if defined( __ANDROID__ ) || defined( __APPLE__ ) + return -1; +#else if(std::string(ms_factory_get_default_video_renderer(NULL)) == "MSOGL") return -1;// Do not test MSOGL as it is already used by default tests else{ g_display_filter = "MSOGL"; return 0; } +#endif } test_suite_t call_video_test_suite = {"Video Call", NULL, NULL, liblinphone_tester_before_each, liblinphone_tester_after_each, sizeof(call_video_tests) / sizeof(call_video_tests[0]), call_video_tests}; diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 2f1d5a9860..0b788efbaf 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -415,9 +415,7 @@ void liblinphone_tester_add_suites() { bc_tester_add_suite(&call_secure_test_suite); #ifdef VIDEO_ENABLED bc_tester_add_suite(&call_video_test_suite); -#if !defined(TARGET_OS_IPHONE) && !defined(__ANDROID__) && !defined(TARGET_OS_MAC) // Mac is not yet fully supported for tests - bc_tester_add_suite(&call_video_msogl_test_suite);// Done only if MSOGL has not been tested in previous test -#endif + bc_tester_add_suite(&call_video_msogl_test_suite);// Conditionals are defined in suite #endif // ifdef VIDEO_ENABLED bc_tester_add_suite(&audio_bypass_suite); bc_tester_add_suite(&audio_routes_test_suite); @@ -520,12 +518,14 @@ void liblinphone_tester_simulate_mire_defunct(MSFilter * filter, bool_t defunct) } #if !TARGET_OS_IPHONE && !(defined(LINPHONE_WINDOWS_PHONE) || defined(LINPHONE_WINDOWS_UNIVERSAL)) - +#if defined(__APPLE__) +int apple_main (int argc, char *argv[]) +#else int main (int argc, char *argv[]) +#endif { int ret = liblinphone_tester_start(argc, argv); liblinphone_tester_stop(); return ret; } - #endif diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index c89af4c8ad..c7a1a00d41 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -50,9 +50,7 @@ extern test_suite_t push_incoming_call_test_suite; #if VIDEO_ENABLED extern test_suite_t call_video_test_suite; -#if !defined(TARGET_OS_IPHONE) && !defined(__ANDROID__) && !defined(TARGET_OS_MAC) // Mac is not yet fully supported for tests extern test_suite_t call_video_msogl_test_suite; -#endif extern test_suite_t call_video_quality_test_suite; #endif // if VIDEO_ENABLED -- GitLab