diff --git a/dConnectDevicePlugin/dConnectDeviceIRKit/dConnectDeviceIRKit/Classes/DPIRKitDevicePlugin.m b/dConnectDevicePlugin/dConnectDeviceIRKit/dConnectDeviceIRKit/Classes/DPIRKitDevicePlugin.m index 93d1d0ac..ee13c6f1 100755 --- a/dConnectDevicePlugin/dConnectDeviceIRKit/dConnectDeviceIRKit/Classes/DPIRKitDevicePlugin.m +++ b/dConnectDevicePlugin/dConnectDeviceIRKit/dConnectDeviceIRKit/Classes/DPIRKitDevicePlugin.m @@ -349,12 +349,16 @@ - (UIViewController *) profile:(DConnectSystemProfile *)sender serviceListViewController.delegate = self; return top; } -- (void)didRemoveService:(DConnectService *)service +- (void)didRemovedService:(DConnectService *)service { - //サービス一覧画面で仮想デバイスが削除されたら、DBからも仮想デバイスを削除する。 - DPIRKitDBManager *mgr = [DPIRKitDBManager sharedInstance]; - [mgr deleteVirtualDevice:service.serviceId]; - [mgr deleteRESTfulRequestForServiceId:service.serviceId]; + // IRKitのServiceIdに.がある場合は仮想デバイスとみなす + NSRange range = [service.serviceId rangeOfString:@"."]; + if (range.location != NSNotFound) { + //サービス一覧画面で仮想デバイスが削除されたら、DBからも仮想デバイスを削除する。 + DPIRKitDBManager *mgr = [DPIRKitDBManager sharedInstance]; + [mgr deleteVirtualDevice:service.serviceId]; + [mgr deleteRESTfulRequestForServiceId:service.serviceId]; + } } - (void)didSelectService:(DConnectService *)service { diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera.xcodeproj/project.pbxproj b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera.xcodeproj/project.pbxproj index f592ccfd..bf114ab9 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera.xcodeproj/project.pbxproj +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera.xcodeproj/project.pbxproj @@ -52,6 +52,8 @@ BE75D3181994A54A00F1BFC9 /* settings_iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = BE75D3171994A54A00F1BFC9 /* settings_iphone.png */; }; BEAFFE4519C94FFA00A98079 /* DConnectSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEAFFE4419C94FFA00A98079 /* DConnectSDK.framework */; }; BEAFFE5C19C96FE100A98079 /* sonycamera01@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = BEAFFE5B19C96FE100A98079 /* sonycamera01@2x.png */; }; + BEC39A151E8BAEEE00F13F40 /* SonyCameraPreview.m in Sources */ = {isa = PBXBuildFile; fileRef = BEC39A141E8BAEEE00F13F40 /* SonyCameraPreview.m */; }; + BEC39A181E8C9E6900F13F40 /* SonyCameraSimpleHttpServer.m in Sources */ = {isa = PBXBuildFile; fileRef = BEC39A171E8C9E6900F13F40 /* SonyCameraSimpleHttpServer.m */; }; BED92A3E1991C11400B61B2F /* SonyCameraDevicePlugin_iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BED92A3D1991C11400B61B2F /* SonyCameraDevicePlugin_iPad.storyboard */; }; BED92A401991D78400B61B2F /* SonyCameraDevicePlugin_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BED92A3F1991D78400B61B2F /* SonyCameraDevicePlugin_iPhone.storyboard */; }; C2540BB2195A7FA000AE012C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2540BB1195A7FA000AE012C /* Foundation.framework */; }; @@ -133,6 +135,10 @@ BE75D3171994A54A00F1BFC9 /* settings_iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = settings_iphone.png; sourceTree = ""; }; BEAFFE4419C94FFA00A98079 /* DConnectSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DConnectSDK.framework; path = ../../dConnectSDK/dConnectSDKForIOS/bin/DConnectSDK.framework; sourceTree = ""; }; BEAFFE5B19C96FE100A98079 /* sonycamera01@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "sonycamera01@2x.png"; sourceTree = ""; }; + BEC39A131E8BAEEE00F13F40 /* SonyCameraPreview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SonyCameraPreview.h; sourceTree = ""; }; + BEC39A141E8BAEEE00F13F40 /* SonyCameraPreview.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SonyCameraPreview.m; sourceTree = ""; }; + BEC39A161E8C9E6900F13F40 /* SonyCameraSimpleHttpServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SonyCameraSimpleHttpServer.h; sourceTree = ""; }; + BEC39A171E8C9E6900F13F40 /* SonyCameraSimpleHttpServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SonyCameraSimpleHttpServer.m; sourceTree = ""; }; BED92A3D1991C11400B61B2F /* SonyCameraDevicePlugin_iPad.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SonyCameraDevicePlugin_iPad.storyboard; sourceTree = ""; }; BED92A3F1991D78400B61B2F /* SonyCameraDevicePlugin_iPhone.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = SonyCameraDevicePlugin_iPhone.storyboard; sourceTree = ""; }; C2540BAE195A7FA000AE012C /* libdConnectDeviceSonyCamera.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdConnectDeviceSonyCamera.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -316,8 +322,8 @@ children = ( C2540C50195A853600AE012C /* sony_camera_remote_sdk */, BE4FDFC9198765B5001A3C86 /* profile */, - C2540C0F195A83D500AE012C /* SonyCameraDevicePlugin.m */, ABB1839019F626B30059E7F8 /* SonyCameraDevicePlugin.h */, + C2540C0F195A83D500AE012C /* SonyCameraDevicePlugin.m */, C2540C71195AAFB400AE012C /* SonyCameraRemoteApiUtil.h */, C2540C72195AAFB400AE012C /* SonyCameraRemoteApiUtil.m */, BE75D3021994884200F1BFC9 /* SonyCameraViewController.h */, @@ -336,6 +342,10 @@ BE75D3151994A44500F1BFC9 /* SonyCameraSettingView04Controller.m */, D6C860461D3B436400232EEF /* SonyCameraService.h */, D6C860471D3B436400232EEF /* SonyCameraService.m */, + BEC39A161E8C9E6900F13F40 /* SonyCameraSimpleHttpServer.h */, + BEC39A171E8C9E6900F13F40 /* SonyCameraSimpleHttpServer.m */, + BEC39A131E8BAEEE00F13F40 /* SonyCameraPreview.h */, + BEC39A141E8BAEEE00F13F40 /* SonyCameraPreview.m */, D662E9A31D4A16B300919C69 /* SonyCameraManager.h */, D662E9A41D4A16B300919C69 /* SonyCameraManager.m */, D6D172721D62E7CD00444337 /* SonyCameraReachability.h */, @@ -589,6 +599,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + BEC39A151E8BAEEE00F13F40 /* SonyCameraPreview.m in Sources */, D6D172741D62E7CD00444337 /* SonyCameraReachability.m in Sources */, D662E99F1D49F61600919C69 /* SonyCameraMediaStreamRecordingProfile.m in Sources */, BE75D30D199495BF00F1BFC9 /* SonyCameraSettingView02Controller.m in Sources */, @@ -613,6 +624,7 @@ BE75D31319949D4F00F1BFC9 /* SonyCameraSettingView03Controller.m in Sources */, BE24CF04197F7BC4007BBC69 /* SampleLiveviewManager.m in Sources */, C2540C68195A853600AE012C /* UdpRequest.m in Sources */, + BEC39A181E8C9E6900F13F40 /* SonyCameraSimpleHttpServer.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -754,6 +766,7 @@ ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "dConnectDeviceSonyCamera/dConnectDeviceSonyCamera-Prefix.pch"; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../../dConnectSDK/dConnectSDKForIOS/DConnectSDK/Dependencies/CocoaAsyncSocket"; ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -771,6 +784,7 @@ ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "dConnectDeviceSonyCamera/dConnectDeviceSonyCamera-Prefix.pch"; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../../dConnectSDK/dConnectSDKForIOS/DConnectSDK/Dependencies/CocoaAsyncSocket"; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDataViewController.h b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDataViewController.h index cf2ad006..8ab3a34e 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDataViewController.h +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDataViewController.h @@ -19,7 +19,7 @@ /*! @brief メインのView。 */ -@property (strong, nonatomic) IBOutlet UIView *mainView; +@property (strong, nonatomic) IBOutlet UIScrollView *mainView; /*! @brief ViewControllerのページ数。 diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDataViewController.m b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDataViewController.m index 6236fd56..e494183e 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDataViewController.m +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDataViewController.m @@ -20,7 +20,7 @@ - (void)viewDidLoad // Do any additional setup after loading the view, typically from a nib. UIScrollView *scrollView = (UIScrollView *)self.mainView; - scrollView.contentInset = UIEdgeInsetsMake(64, 0.0, 0.0, 0); + scrollView.contentInset = UIEdgeInsetsMake(0, 0.0, 0.0, 0); } - (void)didReceiveMemoryWarning diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDevicePlugin.h b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDevicePlugin.h index 886d024e..6c882770 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDevicePlugin.h +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDevicePlugin.h @@ -9,6 +9,11 @@ #import + +@class SonyCameraManager; +@class SonyCameraService; + + /*! @brief SonyCameraデバイスプラグインのデリゲート。 */ @@ -21,6 +26,11 @@ */ - (void) didReceiveDeviceList:(BOOL)discover; +/*! + @brief WiFiの状態が更新されたことを通知. + */ +- (void) didReceiveUpdateDevice; + @end /** @@ -34,22 +44,23 @@ @property (weak, nonatomic) id delegate; /*! - @biref Sony Camera Remote APIに対応したデバイスを探索する。 - - 発見通知は、delegateに設定されたSonyCameraDevicePluginDelegateに通知される。 + @brief SonyCamera制御クラス. */ -- (void) searchSonyCameraDevice; +@property (strong, nonatomic) SonyCameraManager *sonyCameraManager; /*! - @brief デバイスプラグインを停止する。 + @brief Sonyカメラに接続されているか確認を行う. + + @retval YES Sonyカメラに接続されている + @retval NO Sonyカメラに接続されていない */ -- (void) stop; +- (BOOL) isConnectedSonyCamera; /*! - @brief デバイスプラグインが起動中かチェックする。 - @retval YES 起動中 - @retval NO 停止中 + @brief 指定されたサービスを削除します. + + @param[in] servie 削除するサービス */ -- (BOOL) isStarted; +- (void) removeSonyCamera:(SonyCameraService *)service; @end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDevicePlugin.m b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDevicePlugin.m index 1eb40d2f..ad74ccff 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDevicePlugin.m +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraDevicePlugin.m @@ -8,39 +8,17 @@ // #import "SonyCameraDevicePlugin.h" -#import "SonyCameraRemoteApiUtil.h" -#import "SampleRemoteApi.h" -#import "RemoteApiList.h" -#import "DeviceList.h" #import "SonyCameraViewController.h" -#import "SampleLiveviewManager.h" #import "SonyCameraService.h" #import "SonyCameraManager.h" #import "SonyCameraSystemProfile.h" +#import "SonyCameraMediaStreamRecordingProfile.h" #import -#define DPSonyCameraBundle() \ -[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"dConnectDeviceSonyCamera_resources" ofType:@"bundle"]] - /*! @brief Sony Remote Camera用デバイスプラグイン。 */ -@interface SonyCameraDevicePlugin() - -/*! - @brief 1970/1/1からの時間を取得する。 - @return 時間 - */ -- (UInt64) getEpochMilliSeconds; - -/*! - @brief 現在接続されているWifiのSSIDからSony Cameraかチェックする. - @retval YES Sony Cameraの場合 - @retval NO Sony Camera以外 - */ -- (BOOL) checkSSID; +@interface SonyCameraDevicePlugin() @end @@ -52,220 +30,101 @@ @implementation SonyCameraDevicePlugin - (instancetype) init { self = [super initWithObject: self]; if (self) { - self.pluginName = @"Sony Camera (Device Connect Device Plug-in)"; - - (void)[[SonyCameraManager sharedManager] initWithPlugin:self liveViewDelegate:self remoteApiUtilDelegate:self]; - Class key = [self class]; [[DConnectEventManager sharedManagerForClass:key] setController:[DConnectMemoryCacheController new]]; + + self.pluginName = @"Sony Camera (Device Connect Device Plug-in)"; + + self.sonyCameraManager = [[SonyCameraManager alloc] initWithPlugin:self]; + self.sonyCameraManager.delegate = self; - [[SonyCameraManager sharedManager] setServiceProvider: self.serviceProvider]; - [[SonyCameraManager sharedManager] setPlugin:self]; - - // System Profileの追加 + for (SonyCameraService *service in self.sonyCameraManager.sonyCameraServices) { + [self.serviceProvider addService:service]; + } + [self addProfile:[SonyCameraSystemProfile new]]; - - if ([self checkSSID]) { - [self searchSonyCameraDevice]; + if ([self.sonyCameraManager checkSSID]) { + [self.sonyCameraManager connectSonyCamera]; } - __weak typeof(self) _self = self; + + __weak typeof(self) weakSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; UIApplication *application = [UIApplication sharedApplication]; - - [notificationCenter addObserver:_self selector:@selector(applicationWillEnterForeground) - name:UIApplicationWillEnterForegroundNotification - object:application]; - + [notificationCenter addObserver:weakSelf + selector:@selector(applicationWillEnterForeground) + name:UIApplicationWillEnterForegroundNotification + object:application]; }); } return self; } - -#pragma mark - Public Methods - - -- (void) searchSonyCameraDevice { - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - if (manager.searchFlag) { - return; - } - manager.searchFlag = YES; - - // 検索する前にリセットをしておく - [DeviceList reset]; - [[SampleCameraEventObserver getInstance] destroy]; - // Sony Camera デバイスの探索 - SampleDeviceDiscovery* discovery = [SampleDeviceDiscovery new]; - [discovery performSelectorInBackground:@selector(discover:) withObject:self]; -} - -- (void) stop { - [DeviceList reset]; - [[SampleCameraEventObserver getInstance] destroy]; - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - if ([manager.remoteApi isStartedLiveView]) { - [manager.remoteApi actStopLiveView]; - } - manager.remoteApi = nil; -} - -- (BOOL) isStarted { - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - return manager.remoteApi != nil; -} - -#pragma mark - Private Methods - - -- (void) applicationWillEnterForeground -{ - // バックグラウンドから復帰したときの処理 - if ([self checkSSID]) { - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - if (manager.remoteApi == nil) { - [self searchSonyCameraDevice]; - } else { - NSLog(@"TEST: %d", [[SampleCameraEventObserver getInstance] isStarted]); - } - } else { - [self stop]; - } +- (BOOL) isConnectedSonyCamera { + return [self.sonyCameraManager checkSSID]; } -- (UInt64) getEpochMilliSeconds +- (void) removeSonyCamera:(SonyCameraService *)service { - return (UInt64)floor((CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) * 1000.0); + [self.sonyCameraManager removeSonyCamera:service]; } -- (BOOL) checkSSID { - CFArrayRef interfaces = CNCopySupportedInterfaces(); - if (!interfaces) return NO; - if (CFArrayGetCount(interfaces)==0) return NO; - CFDictionaryRef dicRef = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(interfaces, 0)); - if (dicRef) { - NSString *ssid = CFDictionaryGetValue(dicRef, kCNNetworkInfoKeySSID); - if ([ssid hasPrefix:@"DIRECT-"]) { - NSArray *array = @[@"HDR-AS100", @"ILCE-6000", @"DSC-HC60V", @"DSC-HX400", - @"ILCE-5000", @"DSC-QX10", @"DSC-QX100", @"HDR-AS15", - @"HDR-AS30", @"HDR-MV1", @"NEX-5R", @"NEX-5T", @"NEX-6", - @"ILCE-7R/B", @"ILCE-7/B"]; - for (NSString *name in array) { - NSRange searchResult = [ssid rangeOfString:name]; - if (searchResult.location != NSNotFound) { - return YES; - } - } - } - } - return NO; -} - -#pragma mark - SampleDiscoveryDelegate - -- (void) didReceiveDeviceList:(BOOL) discovery { - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - manager.searchFlag = NO; - - if (discovery) { - manager.remoteApi = [SonyCameraRemoteApiUtil new]; - manager.remoteApi.delegate = self; - - // プレビューイベントを持っている場合は、プレビューを再開させる - if ([manager hasDataAvaiableEvent] && ![manager.remoteApi isStartedLiveView]) { - [manager.remoteApi actStartLiveView:self]; - } - } - - // デバイス管理情報更新 - [manager updateManageServices]; +#pragma mark - SonyCameraManagerDelegate Methods +- (void) didDiscoverDeviceList:(BOOL)discovery { [self.delegate didReceiveDeviceList:discovery]; - } -#pragma mark - SampleLiveviewDelegate - - -- (void) didReceivedData:(NSData *)imageData -{ - SonyCameraManager *manager = [SonyCameraManager sharedManager]; +- (void) didTakePicture:(NSString *)postImageUrl { + SonyCameraManager *manager = self.sonyCameraManager; - // プレビューのタイムスライス時間に満たない場合には無視する - UInt64 time = [self getEpochMilliSeconds]; - if (time - manager.previewStart < manager.timeslice) { - return; - } - manager.previewStart = time; + NSString *ssid = [manager getCurrentWifiName]; - manager.mPreviewCount++; - manager.mPreviewCount %= 10; + // イベント作成 + DConnectMessage *photo = [DConnectMessage message]; + [DConnectMediaStreamRecordingProfile setUri:postImageUrl target:photo]; + [DConnectMediaStreamRecordingProfile setMIMEType:@"image/jpg" target:photo]; - // ファイル名を作成 - NSString *fileName = [NSString stringWithFormat:@"preview%d.jpg", manager.mPreviewCount]; - // ファイルを保存 - NSString *uri = [manager.mFileManager createFileForPath:fileName contents:imageData]; - if (uri) { - // イベントの作成 - DConnectMessage *media = [DConnectMessage message]; - [DConnectMediaStreamRecordingProfile setUri:uri target:media]; - [DConnectMediaStreamRecordingProfile setPath:fileName target:media]; - - // イベントの取得 - DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[self class]]; - NSArray *evts = [mgr eventListForServiceId:SERVICE_ID - profile:DConnectMediaStreamRecordingProfileName - attribute:DConnectMediaStreamRecordingProfileAttrOnDataAvailable]; - // イベント送信 - for (DConnectEvent *evt in evts) { - DConnectMessage *eventMsg = [DConnectEventManager createEventMessageWithEvent:evt]; - [eventMsg setMessage:media forKey:DConnectMediaStreamRecordingProfileParamMedia]; - [self sendEvent:eventMsg]; - } + // イベントの取得 + DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[self class]]; + NSArray *evts = [mgr eventListForServiceId:ssid + profile:DConnectMediaStreamRecordingProfileName + attribute:DConnectMediaStreamRecordingProfileAttrOnPhoto]; + // イベント送信 + for (DConnectEvent *evt in evts) { + DConnectMessage *eventMsg = [DConnectEventManager createEventMessageWithEvent:evt]; + [eventMsg setMessage:photo forKey:DConnectMediaStreamRecordingProfileParamPhoto]; + [manager.plugin sendEvent:eventMsg]; } } -- (void) didReceivedError { - [self stop]; - [self searchSonyCameraDevice]; +- (void) didAddedService:(SonyCameraService *)service { + [self.serviceProvider addService:service]; } +- (void) didReceiveWiFiStatus { + if (self.delegate && [self.delegate respondsToSelector:@selector(didReceiveUpdateDevice)]) { + [self.delegate didReceiveUpdateDevice]; + } +} -#pragma mark - SonyCameraRemoteApiUtilDelegate +#pragma mark - DConnectDevicePlugin Methods -- (void) didReceivedImage:(NSString *)imageUrl +- (void) applicationWillEnterForeground { - SonyCameraManager *manager = [SonyCameraManager sharedManager]; + if ([self.sonyCameraManager checkSSID]) { + [self.sonyCameraManager connectSonyCamera]; + } else { + [self.sonyCameraManager disconnectSonyCamera]; + } - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSData *picture = [manager download:imageUrl]; - if (picture) { - NSString *uri = [manager saveFile:picture]; - if (!uri) { - return; - } - - // イベント作成 - DConnectMessage *photo = [DConnectMessage message]; - [DConnectMediaStreamRecordingProfile setUri:uri target:photo]; - [DConnectMediaStreamRecordingProfile setPath:[uri lastPathComponent] target:photo]; - [DConnectMediaStreamRecordingProfile setMIMEType:@"image/png" target:photo]; - - // イベントの取得 - DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[self class]]; - NSArray *evts = [mgr eventListForServiceId:SERVICE_ID - profile:DConnectMediaStreamRecordingProfileName - attribute:DConnectMediaStreamRecordingProfileAttrOnPhoto]; - // イベント送信 - for (DConnectEvent *evt in evts) { - DConnectMessage *eventMsg = [DConnectEventManager createEventMessageWithEvent:evt]; - [eventMsg setMessage:photo forKey:DConnectMediaStreamRecordingProfileParamPhoto]; - [manager.plugin sendEvent:eventMsg]; - } - } - }); + if (self.delegate && [self.delegate respondsToSelector:@selector(didReceiveUpdateDevice)]) { + [self.delegate didReceiveUpdateDevice]; + } } - - (NSString*)iconFilePath:(BOOL)isOnline { NSBundle *bundle = DPSonyCameraBundle(); diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraManager.h b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraManager.h index e6a4c12d..ee1dc354 100644 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraManager.h +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraManager.h @@ -12,90 +12,108 @@ #import "SonyCameraRemoteApiUtil.h" #import "SonyCameraDevicePlugin.h" + +@class SonyCameraService; + + /*! - @define サービスID. + @brief Sonyカメラへの命令の結果を通知するブロック定義. */ -#define SERVICE_ID @"0" +typedef void (^SonyCameraBlock)(int errorCode, NSString *errorMessage); /*! - @brief IDのプレフィックス。 + @brief 写真撮影の結果を通知するブロック定義. */ -extern NSString *const SonyServiceId; +typedef void (^SonyCameraTakePictureBlock)(NSString *uri); /*! - @brief デバイス名。 + @brief プレビューの結果を通知するブロック定義. */ -extern NSString *const SonyDeviceName; +typedef void (^SonyCameraPreviewBlock)(NSString *uri); /*! - @brief ファイルのプレフィックス。 + @brief カメラ状態の取得を通知するブロック定義. */ -extern NSString *const SonyFilePrefix; +typedef void (^SonyCameraStateBlock)(NSString *state, int width, int height); - -@interface SonyCameraManager : NSObject/**/ - /*! - @brief ServiceProvider. + @brief SonyCameraデバイスプラグインのデリゲート。 */ -@property (nonatomic, weak) DConnectServiceProvider *serviceProvider; +@protocol SonyCameraManagerDelegate +@optional /*! - @brief Service生成時に登録するプロファイル(DConnectProfile *)の配列 + @brief デバイスの検索結果を通知. + + @param[in] discovery YESの場合は発見、NOの場合は未発見 */ -@property (nonatomic, weak) SonyCameraDevicePlugin *plugin; +- (void) didDiscoverDeviceList:(BOOL)discovery; /*! - @brief SonyRemoteApi操作用. + @brief 写真撮影が行われた時の通知. + + @param[in] postImageUrl 撮影された画像へのURL */ -@property (nonatomic, strong) SonyCameraRemoteApiUtil *remoteApi; +- (void) didTakePicture:(NSString *)postImageUrl; /*! - @brief ファイル管理クラス。 + @brief デバイスの発見通知。 + @param[in] service 発見されたサービス */ -@property (nonatomic, strong) DConnectFileManager *mFileManager; +- (void) didAddedService:(SonyCameraService *)service; /*! - @brief タイムスライス。 + @brief Wifiの状態が更新されたことを通知. */ -@property (nonatomic) UInt64 timeslice; +- (void) didReceiveWiFiStatus; + +@end + + + /*! - @brief タイムスライス開始時刻。 + @brief Sonyカメラを制御するためのクラス. */ -@property (nonatomic) UInt64 previewStart; +@interface SonyCameraManager : NSObject /*! - @brief プレビューカウント。 + @brief Sonyカメラからのイベントを通知するデリゲート. */ -@property (nonatomic) int mPreviewCount; +@property (nonatomic, weak) id delegate; /*! - @brief サーチフラグ. + @brief Service生成時に登録するプロファイル(DConnectProfile *)の配列 */ -@property (nonatomic) BOOL searchFlag; +@property (nonatomic, weak) SonyCameraDevicePlugin *plugin; /*! - @brief liveViewDelegate. + @brief SonyRemoteApi操作用. */ -@property (nonatomic, weak) id liveViewDelegate; +@property (nonatomic, strong) SonyCameraRemoteApiUtil *remoteApi; /*! - @brief remoteApiUtilDelegate. + @brief ファイル管理クラス。 */ -@property (nonatomic, weak) id remoteApiUtilDelegate; +@property (nonatomic, strong) DConnectFileManager *mFileManager; +/*! + @brief Sonyカメラサービスのリスト. + */ +@property (nonatomic, strong) NSMutableArray *sonyCameraServices; /*! - @brief SonyCameraManagerの共有インスタンスを返す。 - @return SonyCameraManagerの共有インスタンス。 + @brief サーチフラグ. */ -+ (instancetype)sharedManager; +@property (nonatomic) BOOL searchFlag; -- (instancetype)initWithPlugin: (SonyCameraDevicePlugin *) plugin - liveViewDelegate: (id) liveViewDelegate - remoteApiUtilDelegate: (id) remoteApiUtilDelegate; +/*! + @brief SonyCameraを初期化します. + + @param[in] plugin SonyCameraデバイスプラグインのインスタンス + */ +- (instancetype)initWithPlugin:(SonyCameraDevicePlugin *) plugin; /*! @brief 指定されたURLからデータをダウンロードする。 @@ -118,28 +136,142 @@ extern NSString *const SonyFilePrefix; */ - (NSString *) saveFile:(NSData *)data; +/*! + @brief 現在接続されているWiFiアクセスポイントがSonyカメラのSSIDか確認を行う. + + @retval YES Sonyカメラのアクセスポイントの場合 + @retval NO Sonyカメラ以外のアクセスポイントの場合 + */ +- (BOOL) checkSSID; + +/*! + @brief 現在接続されているWiFiのSSIDを取得します. + + @retval 接続中のWiFiのSSID + @retval nil 取得に失敗した場合 + */ +- (NSString *)getCurrentWifiName; + +/*! + @brief 指定されたサービスを削除します. + + @param[in] service 削除するサービス + */ +- (void) removeSonyCamera:(SonyCameraService *)service; + +/*! + @brief Sonyカメラに接続を行います. + */ +- (void) connectSonyCamera; + +/*! + @brief Sonyカメラから切断します. + */ +- (void) disconnectSonyCamera; /*! - @brief 選択されたサービスIDに対応するカメラを選択する. + @brief 指定されたサービスIDに接続されているか確認を行う. + @param serviceId サービスID - @param response レスポンス - @retval YES 選択できた場合 - @retval NO 選択できなかった場合 + @retval YES 接続されている + @retval NO 接続されていない + */ +- (BOOL) isConnectedService:(NSString *)serviceId; + +/*! + @brief Sonyカメラの撮影中か確認を行う. + + @retval YES 撮影中 + @retval NO IDLE + */ +- (BOOL) isRecording; + +/*! + @brief Sonyカメラがプレビューを表示中か確認を行う. + + @retval YES 撮影中 + @retval NO IDLE + */ +- (BOOL) isPreview; + +/*! + @brief ズームをサポートしているかを確認します. + + @retval YES サポートしている + @retval NO サポートしていない + */ +- (BOOL) isSupportedZoom; + +/*! + @brief 写真撮影をサポートしているか確認します. + + @retval YES サポートしている + @retval NO サポートしていない + */ +- (BOOL) isSupportedPicture; + +/*! + @brief 動画撮影をサポートしているか確認します. + + @retval YES サポートしている + @retval NO サポートしていない + */ +- (BOOL) isSupportedRecording; + +/*! + @brief カメラ状態の取得を要求します. + + @param block カメラ状態の取得の結果を通知するブロック. */ -- (BOOL) selectServiceId:(NSString *)serviceId response:(DConnectResponseMessage *)response; +- (void) getCameraState:(SonyCameraStateBlock)block; +/*! + @brief 写真撮影を要求します. + + 写真撮影の結果をブロックに通知します. + @param block 写真撮影の結果を通知するブロック. + */ +- (void) takePicture:(SonyCameraTakePictureBlock)block; /*! - @brief プレビューイベントを持っているかをチェックする. - @retval YES 持っている - @retval NO 持っていない + @brief プレビューを開始します. + + @param timeSlice タイムスライス + @param block プレビューの通知を行うブロック */ -- (BOOL) hasDataAvaiableEvent; +- (void) startPreviewWithTimeSlice:(NSNumber *)timeSlice block:(SonyCameraPreviewBlock)block; /*! - @brief デバイス管理情報更新 + @brief プレビューを停止します. */ -- (void) updateManageServices; +- (void) stopPreview; + +/*! + @brief 動画撮影を開始要求を行います. + + @param block 動画撮影開始要求の結果を通知するブロック + */ +- (void) startMovieRec:(SonyCameraBlock)block; + +/*! + @brief 動画撮影を停止要求を行います. + + @param block 動画撮影停止要求の結果を通知するブロック + */ +- (void) stopMovieRec:(SonyCameraBlock)block; + +/*! + @brief ズームを要求します. + + @param direction ズームイン・ズームアウト(in,out) + @param movement ズームする単位 (max, 1shot, min) + @param block 結果を通知するブロック + */ +- (void) setZoomByDirection:(NSString *)direction + movement:(NSString *)movement + block:(SonyCameraBlock)block; + +- (double) getZoom; @end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraManager.m b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraManager.m index 8c00dc80..234e1aa9 100644 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraManager.m +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraManager.m @@ -9,67 +9,85 @@ #import "SonyCameraManager.h" #import "DeviceList.h" +#import "RemoteApiList.h" #import #import "SonyCameraService.h" #import "SonyCameraReachability.h" +#import +#import +#import "SonyCameraPreview.h" /*! - @brief IDのプレフィックス。 + @brief ファイルのプレフィックス。 */ -NSString *const SonyServiceId = @"sony_camera_"; +#define SonyFilePrefix @"sony" /*! - @brief デバイス名。 + @brief サービスIDを保存するキー名. */ -NSString *const SonyDeviceName = @"Sony Camera"; +#define SONY_CAMERA_ID @"sony_came_id" /*! - @brief ファイルのプレフィックス。 + @brief サービス名を保存するキー名. */ -NSString *const SonyFilePrefix = @"sony"; +#define SONY_CAMERA_NAME @"sony_came_name" -@interface SonyCameraManager() +@interface SonyCameraDevice : NSObject -@property (nonatomic, strong) SonyCameraReachability *reachability; +@property (nonatomic) NSString *serviceId; +@property (nonatomic) NSString *deviceName; @end -@implementation SonyCameraManager +@implementation SonyCameraDevice -// share instance -+ (instancetype)sharedManager -{ - static id sharedInstance; - static dispatch_once_t onceSonyCameraToken; - dispatch_once(&onceSonyCameraToken, ^{ - sharedInstance = [self new]; - }); - return sharedInstance; +- (id) initWithCoder:(NSCoder *)coder { + self = [super init]; + if (self) { + self.serviceId = [coder decodeObjectForKey:SONY_CAMERA_ID]; + self.deviceName = [coder decodeObjectForKey:SONY_CAMERA_NAME]; + } + return self; +} + +- (void) encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:self.serviceId forKey:SONY_CAMERA_ID]; + [coder encodeObject:self.deviceName forKey:SONY_CAMERA_NAME]; } +@end + + + +@interface SonyCameraManager() + +@property (nonatomic, strong) SonyCameraReachability *reachability; +@property (nonatomic, strong) SonyCameraPreview *sonyCameraPreview; + +@end + +@implementation SonyCameraManager + // init -- (instancetype)initWithPlugin: (SonyCameraDevicePlugin *) plugin - liveViewDelegate: (id) liveViewDelegate - remoteApiUtilDelegate: (id) remoteApiUtilDelegate +- (instancetype)initWithPlugin:(SonyCameraDevicePlugin *) plugin { self = [super init]; if (self) { - self.timeslice = 200; - self.previewStart = 0; self.remoteApi = nil; self.searchFlag = NO; self.mFileManager = [DConnectFileManager fileManagerForPlugin:plugin]; self.plugin = plugin; - self.liveViewDelegate = liveViewDelegate; - self.remoteApiUtilDelegate = remoteApiUtilDelegate; - + self.sonyCameraServices = [NSMutableArray array]; + self.sonyCameraPreview = nil; + + [self loadSonyCameraDevices]; + // Reachabilityの初期処理 self.reachability = [SonyCameraReachability reachabilityWithHostName: @"www.google.com"]; - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(notifiedNetworkStatus:) - name:kReachabilityChangedNotification - object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(notifiedNetworkStatus:) + name:kReachabilityChangedNotification + object:nil]; [self.reachability startNotifier]; } return self; @@ -80,60 +98,377 @@ - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self name:kReachabilityChangedNotification object:nil]; } -// デバイス管理情報更新 -- (void) updateManageServices { - @synchronized(self) { +- (BOOL) checkSSID { + CFArrayRef interfaces = CNCopySupportedInterfaces(); + if (!interfaces) return NO; + if (CFArrayGetCount(interfaces)==0) return NO; + CFDictionaryRef dicRef = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(interfaces, 0)); + if (dicRef) { + NSString *ssid = CFDictionaryGetValue(dicRef, kCNNetworkInfoKeySSID); + if ([ssid hasPrefix:@"DIRECT-"]) { + NSArray *array = @[@"HDR-AS100", @"ILCE-6000", @"DSC-HC60V", @"DSC-HX400", + @"ILCE-5000", @"DSC-QX10", @"DSC-QX100", @"HDR-AS15", + @"HDR-AS30", @"HDR-MV1", @"NEX-5R", @"NEX-5T", @"NEX-6", + @"ILCE-7R/B", @"ILCE-7/B"]; + for (NSString *name in array) { + NSRange searchResult = [ssid rangeOfString:name]; + if (searchResult.location != NSNotFound) { + return YES; + } + } + } + } + return NO; +} + +- (NSString *)getCurrentWifiName { + NSString *wifiName = @"Not Found"; + CFArrayRef myArray = CNCopySupportedInterfaces(); + if (myArray != nil) { + CFDictionaryRef myDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray, 0)); + if (myDict != nil) { + NSDictionary *dict = (NSDictionary*)CFBridgingRelease(myDict); + wifiName = [dict valueForKey:@"SSID"]; + } + } + return wifiName; +} + +- (void) removeSonyCamera:(SonyCameraService *)service +{ + [self.sonyCameraServices removeObject:service]; + [self saveSonyCameraDevices]; +} + +- (void) connectSonyCamera { + if (self.searchFlag) { + return; + } + self.searchFlag = YES; + + [self disconnectSonyCamera]; + + SampleDeviceDiscovery* discovery = [SampleDeviceDiscovery new]; + [discovery performSelectorInBackground:@selector(discover:) withObject:self]; +} + +- (void) disconnectSonyCamera { + [self setOnlineStatus]; + + if (self.remoteApi) { + [self.remoteApi destroy]; + self.remoteApi = nil; + } + + [DeviceList reset]; +} + +- (BOOL) isConnectedService:(NSString *)serviceId { + NSString *ssid = [self getCurrentWifiName]; + return self.remoteApi && ssid && [ssid isEqualToString:serviceId]; +} + +- (BOOL) isRecording { + return [SonyCameraStatusMovieRecording isEqualToString:self.remoteApi.cameraStatus]; +} + +- (BOOL) isPreview { + return self.sonyCameraPreview && [self.sonyCameraPreview isRunning]; +} + +- (BOOL) isSupportedZoom { + return [self.remoteApi isApiAvailable:API_actZoom]; +} + +- (BOOL) isSupportedPicture { + return [self.remoteApi isApiAvailable:API_actTakePicture]; +} + +- (BOOL) isSupportedRecording { + return [self.remoteApi isApiAvailable:API_stopRecMode]; +} + +- (void) getCameraState:(SonyCameraStateBlock)block { + __block typeof(self) weakSelf = self; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSString *cameraStatus = weakSelf.remoteApi.cameraStatus; + NSString *status = nil; + int width = 0; + int height = 0; - // ServiceProvider未登録なら処理しない - if (!self.serviceProvider) { - return; + if ([cameraStatus isEqualToString:@"Error"] || + [cameraStatus isEqualToString:@"NotReady"] || + [cameraStatus isEqualToString:@"MovieSaving"] || + [cameraStatus isEqualToString:@"AudioSaving"] || + [cameraStatus isEqualToString:@"StillSaving"]) { + status = DConnectMediaStreamRecordingProfileRecorderStateInactive; + } else if ([cameraStatus isEqualToString:@"StillCapturing"] || + [cameraStatus isEqualToString:@"MediaRecording"] || + [cameraStatus isEqualToString:@"AudioRecording"] || + [cameraStatus isEqualToString:@"IntervalRecording"]) { + status = DConnectMediaStreamRecordingProfileRecorderStateRecording; + } else if ([cameraStatus isEqualToString:@"MovieWaitRecStart"] || + [cameraStatus isEqualToString:@"MoviewWaitRecStop"] || + [cameraStatus isEqualToString:@"AudioWaitRecStart"] || + [cameraStatus isEqualToString:@"AudioRecWaitRecStop"] || + [cameraStatus isEqualToString:@"IntervalWaitRecStart"] || + [cameraStatus isEqualToString:@"IntervalWaitRecStop"]) { + status = DConnectMediaStreamRecordingProfileRecorderStatePaused; + } else { + status = DConnectMediaStreamRecordingProfileRecorderStateUnknown; } - int deviceCount = (int)[DeviceList getSize]; + NSDictionary *dic = [weakSelf.remoteApi getStillSize]; + if (dic) { + NSString *aspect = dic[@"aspect"]; + NSString *size = dic[@"size"]; + + NSArray *sizes = [aspect componentsSeparatedByString:@":"]; + NSString *widthString = sizes[0]; + NSString *heightString = sizes[1]; + int stillSize = 0; + + width = [widthString intValue]; + height = [heightString intValue]; + + if ([aspect isEqualToString:@"1:1"]) { + if ([size isEqualToString:@"3.7M"]) { + stillSize = (1920 * 1920) / (width * height); + } else if ([size isEqualToString:@"13M"]) { + stillSize = (3648 * 3648) / (width * height); + } + } else if ([aspect isEqualToString:@"3:2"]) { + if ([size isEqualToString:@"20M"]) { + stillSize = (5472 * 3648) / (width * height); + } else if ([size isEqualToString:@"5M"]) { + stillSize = (2736 * 1824) / (width * height); + } + } else if ([aspect isEqualToString:@"4:3"]) { + if ([size isEqualToString:@"18M"]) { + stillSize = (4864 * 3648) / (width * height); + } else if ([size isEqualToString:@"5M"]) { + stillSize = (2592 * 1944) / (width * height); + } + } else if ([aspect isEqualToString:@"16:9"]) { + if ([size isEqualToString:@"17M"]) { + stillSize = (5472 * 3080) / (width * height); + } else if ([size isEqualToString:@"4.2M"]) { + stillSize = (2720 * 1528) / (width * height); + } + } + + if (stillSize == 0) { + width = 0; + height = 0; + } else { + width = width * stillSize; + height = height * stillSize; + } + } - // ServiceProviderに存在するサービスが検出されなかったならオフラインにする - for (DConnectService *service in [self.serviceProvider services]) { - NSString *serviceId = [service serviceId]; + block(status, width, height); + }); +} + - // SonyCamera以外は対象外 - if ([[service name] localizedCaseInsensitiveCompare: SonyDeviceName] != NSOrderedSame) { - continue; +- (void) takePicture:(SonyCameraTakePictureBlock)block { + __block typeof(self) weakSelf = self; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + // 写真モードではない場合には、モードを切り替え + if (![SonyCameraShootModePicture isEqualToString:weakSelf.remoteApi.shootMode]) { + if (![self.remoteApi actSetShootMode:SonyCameraShootModePicture]) { + block(nil); + return; + } + } + + NSDictionary *dict = [weakSelf.remoteApi actTakePicture]; + if (dict == nil) { + block(nil); + } else { + NSString *errorMessage = @""; + NSInteger errorCode = -1; + NSArray *resultArray = dict[@"result"]; + NSArray *errorArray = dict[@"error"]; + if (errorArray && errorArray.count > 0) { + errorCode = (NSInteger) errorArray[0]; + errorMessage = errorArray[1]; } - // ServiceProviderにあって最新のリストに無い場合はオフラインにする。有ればオンラインにする - BOOL isFindDevice = NO; - for (int deviceIndex = 0; deviceIndex < deviceCount; deviceIndex ++) { - NSString *deviceServiceId = [NSString stringWithFormat:@"%d", deviceIndex]; - if (deviceServiceId && [serviceId localizedCaseInsensitiveCompare: deviceServiceId] == NSOrderedSame) { - isFindDevice = YES; - break; + if (resultArray.count <= 0 && errorCode >= 0) { + block(nil); + } else { + NSArray *arr = resultArray[0]; + NSString *postImageUrl = arr[0]; + if (postImageUrl) { + block([weakSelf saveFileFromURL:postImageUrl]); + } else { + block(nil); } } - if (isFindDevice) { - [service setOnline: YES]; - } else { - [service setOnline: NO]; + } + }); +} + +- (void) startPreviewWithTimeSlice:(NSNumber *)timeSlice block:(SonyCameraPreviewBlock)block { + __block typeof(self) weakSelf = self; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + if (weakSelf.sonyCameraPreview) { + [weakSelf.sonyCameraPreview stopPreview]; + weakSelf.sonyCameraPreview = nil; + } + + weakSelf.sonyCameraPreview = [[SonyCameraPreview alloc] initWithRemoteApi:weakSelf.remoteApi]; + BOOL result = [weakSelf.sonyCameraPreview startPreviewWithTimeSlice:timeSlice]; + if (result) { + block([weakSelf.sonyCameraPreview getUrl]); + } else { + block(nil); + } + }); +} + +- (void) stopPreview { + __block typeof(self) weakSelf = self; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + if (weakSelf.sonyCameraPreview) { + [weakSelf.sonyCameraPreview stopPreview]; + weakSelf.sonyCameraPreview = nil; + } + }); +} + +- (void) startMovieRec:(SonyCameraBlock)block { + __block typeof(self) weakSelf = self; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + + // 動画撮影モードではない場合には、モードを切り替え + if (![SonyCameraShootModeMovie isEqualToString:weakSelf.remoteApi.shootMode]) { + if (![weakSelf.remoteApi actSetShootMode:SonyCameraShootModeMovie]) { + block(0, nil); + return; } } + + NSDictionary *dict = [weakSelf.remoteApi startMovieRec]; + if (dict) { + block(0, nil); + } else { + block(1, @"error"); + } + }); +} + +- (void) stopMovieRec:(SonyCameraBlock)block { + __block typeof(self) weakSelf = self; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSDictionary *dict = [weakSelf.remoteApi stopMovieRec]; + if (dict) { + block(0, nil); + } else { + block(1, @"error"); + } + }); +} + +- (void) setZoomByDirection:(NSString *)direction + movement:(NSString *)movement + block:(SonyCameraBlock)block { + __block typeof(self) weakSelf = self; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSString *tmpMovement = movement; + if ([movement isEqualToString:@"max"]) { + tmpMovement = @"start"; + } - // サービス未登録なら登録する - for (int deviceIndex = 0; deviceIndex < deviceCount; deviceIndex ++) { - NSString *deviceServiceId = [NSString stringWithFormat:@"%d", deviceIndex]; - NSString *deviceName = SonyDeviceName; - if (![self.serviceProvider service: deviceServiceId]) { - SonyCameraService *service = [[SonyCameraService alloc] initWithServiceId:deviceServiceId - deviceName:deviceName - plugin: self.plugin - liveViewDelegate:self.liveViewDelegate - remoteApiUtilDelegate:self.remoteApiUtilDelegate]; - [self.serviceProvider addService: service]; - [service setOnline: YES]; + NSDictionary *dict = [weakSelf.remoteApi actZoom:direction movement:tmpMovement]; + if (dict == nil) { + block(1, @"timeout"); + } else { + NSString *errorMessage = @""; + NSInteger errorCode = -1; + NSArray *resultArray = dict[@"result"]; + NSArray *errorArray = dict[@"error"]; + if (errorArray && errorArray.count > 0) { + errorCode = (NSInteger) errorArray[0]; + errorMessage = errorArray[1]; } + + if (resultArray.count <= 0 && errorCode >= 0) { + block(1, errorMessage); + } else { + block(0, nil); + } + } + }); +} + +- (double) getZoom { + return self.remoteApi.zoomPosition; +} + + +#pragma mark - Private Methods + +- (void) setShootMode:(NSString *)mode block:(SonyCameraBlock)block { + if ([self.remoteApi actSetShootMode:mode]) { + block(0, nil); + } else { + block(1, @"error"); + } +} + +- (void) setOnlineStatus { + __block NSString *ssid = [self getCurrentWifiName]; + + [self.sonyCameraServices enumerateObjectsUsingBlock:^(SonyCameraService *obj, NSUInteger idx, BOOL *stop) { + if (ssid) { + [obj setOnline:[obj.serviceId isEqualToString:ssid]]; + } else { + [obj setOnline:NO]; } + }]; + + if (self.delegate && [self.delegate respondsToSelector:@selector(didReceiveWiFiStatus)]) { + [self.delegate didReceiveWiFiStatus]; } } -#pragma mark - Private Methods - +- (SonyCameraService *) foundSonyCamera { + __block NSString *ssid = [self getCurrentWifiName]; + __block SonyCameraService *result = nil; + + if (!ssid) { + return nil; + } + + [self.sonyCameraServices enumerateObjectsUsingBlock:^(SonyCameraService *obj, NSUInteger idx, BOOL *stop) { + if ([obj.serviceId isEqualToString:ssid]) { + result = obj; + *stop = YES; + } + }]; + + // リストにSonyCameraが存在しない場合 + if (!result) { + result = [[SonyCameraService alloc] initWithServiceId:ssid + deviceName:ssid + plugin:self.plugin]; + [self.sonyCameraServices addObject:result]; + [self.delegate didAddedService:result]; + [self saveSonyCameraDevices]; + } + + return result; +} - (NSData *) download:(NSString *)requestURL { NSURL *downoadUrl = [NSURL URLWithString:requestURL]; @@ -143,49 +478,107 @@ - (NSData *) download:(NSString *)requestURL { - (NSString *) saveFile:(NSData *)data { + if (!data) { + return nil; + } + // ファイル名作成 NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"JST"]]; [formatter setDateFormat:@"yyyyMMdd_HHmmss"]; NSString *dateStr = [formatter stringFromDate:[NSDate date]]; - NSString *fileName = [NSString stringWithFormat:@"%@_%@.png", SonyFilePrefix, dateStr]; - + NSString *fileName = [NSString stringWithFormat:@"%@_%@.jpg", SonyFilePrefix, dateStr]; // ファイルを保存 - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - return [manager.mFileManager createFileForPath:fileName contents:data]; + return [self.mFileManager createFileForPath:fileName contents:data]; } -- (BOOL) selectServiceId:(NSString *)serviceId response:(DConnectResponseMessage *)response { - // サービスIDの存在チェック - if (!serviceId) { - [response setErrorToEmptyServiceId]; - return NO; - } - - // デバイスが存在しない - if ([DeviceList getSize] <= 0) { - [response setErrorToNotFoundService]; - return NO; +- (NSString *) saveFileFromURL:(NSString *)requestURL { + return [self saveFile:[self download:requestURL]]; +} + +- (void) saveSonyCameraDevices +{ + NSMutableArray *array = [NSMutableArray array]; + for (SonyCameraService *service in self.sonyCameraServices) { + SonyCameraDevice *device = [SonyCameraDevice new]; + device.serviceId = service.serviceId; + device.deviceName = service.name; + [array addObject:device]; } - // デバイス選択 - NSInteger idx = [serviceId integerValue]; - [DeviceList selectDeviceAt:idx]; + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentDirectory = [paths objectAtIndex:0]; + NSString *path = [documentDirectory stringByAppendingPathComponent:@"SonyCamera.dat"]; - return YES; + if (array.count == 0) { + [[NSFileManager new] removeItemAtPath:path error:NULL]; + } else { + NSMutableData *data = [NSMutableData data]; + + NSKeyedArchiver *encoder = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; + [encoder encodeObject:array forKey:@"devices"]; + [encoder finishEncoding]; + + [data writeToFile:path atomically:YES]; + } } -- (BOOL) hasDataAvaiableEvent { - DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[self.plugin class]]; - NSArray *evts = [mgr eventListForServiceId:SERVICE_ID - profile:DConnectMediaStreamRecordingProfileName - attribute:DConnectMediaStreamRecordingProfileAttrOnDataAvailable]; - return evts.count > 0; +- (void) loadSonyCameraDevices +{ + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *documentDirectory = [paths objectAtIndex:0]; + NSString *path = [documentDirectory stringByAppendingPathComponent:@"SonyCamera.dat"]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if ([fileManager fileExistsAtPath:path]) { + NSMutableData *data = [NSMutableData dataWithContentsOfFile:path]; + NSKeyedUnarchiver *decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; + NSArray *array = [decoder decodeObjectForKey:@"devices"]; + + for (SonyCameraDevice *device in array) { + SonyCameraService *service = [[SonyCameraService alloc] initWithServiceId:device.serviceId + deviceName:device.deviceName + plugin:self.plugin]; + [self.sonyCameraServices addObject:service]; + } + } } +#pragma mark - SonyCameraReachability Methods + // 通知を受け取るメソッド --(void)notifiedNetworkStatus:(NSNotification *)notification { - [self updateManageServices]; +-(void) notifiedNetworkStatus:(NSNotification *)notification { + if ([self checkSSID]) { + [self connectSonyCamera]; + } else { + [self disconnectSonyCamera]; + } +} + + +#pragma mark - SampleDiscoveryDelegate + +- (void) didReceiveDeviceList:(BOOL)discovery { + self.searchFlag = NO; + + if (discovery) { + SonyCameraService *service = [self foundSonyCamera]; + if (service) { + [service setOnline:YES]; + } + + [DeviceList selectDeviceAt:0]; + + self.remoteApi = [SonyCameraRemoteApiUtil new]; + self.remoteApi.delegate = self; + } + + [self.delegate didDiscoverDeviceList:discovery]; +} + +#pragma mark - SonyCameraRemoteApiUtilDelegate + +- (void) didReceivedImage:(NSString *)imageUrl { + [self.delegate didTakePicture:imageUrl]; } @end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraPreview.h b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraPreview.h new file mode 100644 index 00000000..8c8b4d1e --- /dev/null +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraPreview.h @@ -0,0 +1,50 @@ +// +// SonyCameraPreview.h +// dConnectDeviceSonyCamera +// +// Copyright (c) 2017 NTT DOCOMO, INC. +// Released under the MIT license +// http://opensource.org/licenses/mit-license.php +// + +#import + +@class SonyCameraRemoteApiUtil; + +/*! + @brief Sonyカメラからのプレビューを制御するためのクラス. + */ +@interface SonyCameraPreview : NSObject + +- (instancetype)initWithRemoteApi:(SonyCameraRemoteApiUtil *)remoteApi; + +/*! + @brief プレビューを開始します. + + @retval YES プレビューの開始に成功 + @retval NO プレビューの開始に失敗 + */ +- (BOOL) startPreviewWithTimeSlice:(NSNumber *)timeSlice; + +/*! + @brief プレビューを停止します. + */ +- (void) stopPreview; + +/*! + @brief プレビュー再生中フラグを取得します. + + @retval YSE プレビュー再生中 + @retval NO プレビュー停止中 + */ +- (BOOL) isRunning; + +/*! + @brief プレビュー画像を配信するサーバへのURLを取得します. + + @retval プレビュー画像を配信するサーバへのURL + @retval サーバが起動していない場合にはnil + */ +- (NSString *)getUrl; + +@end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraPreview.m b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraPreview.m new file mode 100644 index 00000000..599b698d --- /dev/null +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraPreview.m @@ -0,0 +1,114 @@ +// +// SonyCameraPreview.m +// dConnectDeviceSonyCamera +// +// Copyright (c) 2017 NTT DOCOMO, INC. +// Released under the MIT license +// http://opensource.org/licenses/mit-license.php +// + +#import "SonyCameraPreview.h" +#import "SampleRemoteApi.h" +#import "RemoteApiList.h" +#import "DeviceList.h" +#import "SampleLiveviewManager.h" +#import "SonyCameraRemoteApiUtil.h" +#import "SonyCameraSimpleHttpServer.h" + + +@interface SonyCameraPreview () + +@end + + +@implementation SonyCameraPreview { + SonyCameraRemoteApiUtil *_remoteApi; + SonyCameraSimpleHttpServer *_httpServer; +} + +- (instancetype)initWithRemoteApi:(SonyCameraRemoteApiUtil *)remoteApi +{ + self = [super init]; + if (self) { + _remoteApi = remoteApi; + _httpServer = nil; + } + return self; +} + +#pragma mark - Public Methods + +- (BOOL) startPreviewWithTimeSlice:(NSNumber *)timeSlice +{ + if (_httpServer) { + [_httpServer stop]; + _httpServer = nil; + } + + _httpServer = [SonyCameraSimpleHttpServer new]; + _httpServer.listenPort = 10000; + if (timeSlice) { + _httpServer.timeSlice = [timeSlice integerValue]; + } + BOOL result = [_httpServer start]; + if (!result) { + return NO; + } + + result = [self startLiveView]; + if (!result) { + [_httpServer stop]; + _httpServer = nil; + return NO; + } + + return YES; +} + +- (void) stopPreview +{ + if (_httpServer) { + [_httpServer stop]; + _httpServer = nil; + } + + if ([_remoteApi isStartedLiveView]) { + [_remoteApi actStopLiveView]; + } +} + +- (BOOL) isRunning +{ + return _httpServer && [_remoteApi isStartedLiveView]; +} + +- (NSString *)getUrl +{ + if (_httpServer) { + return [_httpServer getUrl]; + } + return nil; +} + + +#pragma mark - Private Methods + +- (BOOL) startLiveView { + return [_remoteApi actStartLiveView:self]; +} + +#pragma mark - SampleLiveviewDelegate Methods + +- (void) didReceivedData:(NSData *)imageData +{ + if (_httpServer) { + [_httpServer offerData:imageData]; + } +} + +- (void) didReceivedError +{ + DCLogInfo(@"Preview occurred an error."); +} + +@end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraRemoteApiUtil.h b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraRemoteApiUtil.h index 4bd1c6f9..63bbf905 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraRemoteApiUtil.h +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraRemoteApiUtil.h @@ -60,7 +60,8 @@ extern NSString *const SonyCameraShootModePicture; */ @property (nonatomic) NSString *cameraStatus; -/*! @brief カメラの撮影モード. +/*! + @brief カメラの撮影モード. */ @property (nonatomic) NSString *shootMode; @@ -69,7 +70,13 @@ extern NSString *const SonyCameraShootModePicture; */ @property (nonatomic) double zoomPosition; -/*! @brief APIリストを取得する. +/*! + @brief SampleCameraEventObserverを破棄します. + */ +- (void) destroy; + +/*! + @brief APIリストを取得する. */ - (void) actGetApiList; diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraRemoteApiUtil.m b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraRemoteApiUtil.m index ee779fb3..762c1d96 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraRemoteApiUtil.m +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraRemoteApiUtil.m @@ -63,6 +63,11 @@ - (id) init #pragma mark - Public Methods - +- (void) destroy +{ + [[SampleCameraEventObserver getInstance] destroy]; +} + - (void) actGetApiList { [SampleRemoteApi getAvailableApiList:self isSync:NO]; @@ -308,8 +313,6 @@ - (BOOL) setDate:(NSString *)date { #pragma mark - HttpAsynchronousRequestParserDelegate Methods - - (void) parseMessage:(NSData *)response apiName:(NSString *)apiName { -// NSString *responseText = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding]; - NSError *error; NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableContainers @@ -319,7 +322,7 @@ - (void) parseMessage:(NSData *)response apiName:(NSString *)apiName { NSInteger errorCode = -1; NSInteger apiId = -1; if (error) { - NSLog(@"QX10DevicePlugin parseMessage error parsing JSON string"); + return; } else { apiId = (NSInteger) dict[@"id"]; resultArray = dict[@"result"]; diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraService.h b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraService.h index ec5ee0f1..16995b7b 100644 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraService.h +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraService.h @@ -13,6 +13,8 @@ @interface SonyCameraService : DConnectService -- (instancetype) initWithServiceId: (NSString *) serviceId deviceName: (NSString *) deviceName plugin: (id) plugin liveViewDelegate: (id) liveViewDelegate remoteApiUtilDelegate:(id) remoteApiUtilDelegate; +- (instancetype) initWithServiceId:(NSString *)serviceId + deviceName:(NSString *)deviceName + plugin:(id)plugin; @end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraService.m b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraService.m index 937d079d..47aa2e4e 100644 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraService.m +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraService.m @@ -17,21 +17,22 @@ @implementation SonyCameraService -- (instancetype) initWithServiceId: (NSString *) serviceId deviceName: (NSString *) deviceName plugin: (id) plugin liveViewDelegate: (id) liveViewDelegate remoteApiUtilDelegate:(id) remoteApiUtilDelegate { - - self = [super initWithServiceId: serviceId plugin: plugin]; +- (instancetype) initWithServiceId:(NSString *) serviceId + deviceName:(NSString *) deviceName + plugin:(id) plugin { + self = [super initWithServiceId:serviceId plugin:plugin]; if (self) { - [self setName: deviceName]; - [self setNetworkType: DConnectServiceDiscoveryProfileNetworkTypeWiFi]; - [self setOnline: YES]; - - [self addProfile: [DConnectSystemProfile new]]; - [self addProfile: [[SonyCameraMediaStreamRecordingProfile alloc] initWithLiveViewDelegate: liveViewDelegate remoteApiUtilDelegate: remoteApiUtilDelegate]]; - [self addProfile: [SonyCameraCameraProfile new]]; + [self setName:deviceName]; + [self setNetworkType:DConnectServiceDiscoveryProfileNetworkTypeWiFi]; + [self setOnline:NO]; + [self addProfile:[DConnectSystemProfile new]]; + [self addProfile:[SonyCameraMediaStreamRecordingProfile new]]; + [self addProfile:[SonyCameraCameraProfile new]]; } return self; } + #pragma mark - DConnectServiceInformationProfileDataSource Implement. - (DConnectServiceInformationProfileConnectState)profile:(DConnectServiceInformationProfile *)profile diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraSettingView04Controller.m b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraSettingView04Controller.m index 846e8288..ab24dcc8 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraSettingView04Controller.m +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraSettingView04Controller.m @@ -30,13 +30,8 @@ - (void)viewDidLoad // 角丸にする self.searchBtn.layer.cornerRadius = 16; - // Sony Cameraに接続されているかチェックする - BOOL exist = [self.deviceplugin isStarted]; - if (exist) { - self.ssidLabel.text = @"Sony Camera Connected."; - } else { - self.ssidLabel.text = @"Not Found Sony Camera."; - } + // 接続状態を確認 + [self checkConnectSonyCamera]; // デリゲートを設定 self.deviceplugin.delegate = self; @@ -48,6 +43,10 @@ - (void)didReceiveMemoryWarning // Dispose of any resources that can be recreated. } +- (void)viewWillAppear:(BOOL)animated +{ +} + /* #pragma mark - Navigation @@ -60,21 +59,35 @@ - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender */ +- (void) checkConnectSonyCamera { + if (![self.deviceplugin isConnectedSonyCamera]) { + self.ssidLabel.text = @"Not Found Sony Camera."; + } else { + self.ssidLabel.text = @"Sony Camera Connected."; + } +} + +// WiFi設定画面を開く確認を行う +- (void) confirmOpenWiFiSettings +{ + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Sonyカメラ設定" + message:@"WiFi設定画面でSonyカメラに接続してください。" + preferredStyle:UIAlertControllerStyleAlert]; + + [alert addAction:[UIAlertAction actionWithTitle:@"閉じる" style:UIAlertActionStyleDefault handler:nil]]; + [alert addAction:[UIAlertAction actionWithTitle:@"設定を開く" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { + NSURL *url = [NSURL URLWithString:@"App-Prefs:root=WIFI"]; + [[UIApplication sharedApplication] openURL:url]; + }]]; + + [self presentViewController:alert animated:YES completion:nil]; +} + #pragma mark - Action methods - (IBAction) searchBtnDidPushed:(id)sender { - if (![self.deviceplugin isStarted]) { - [self.deviceplugin searchSonyCameraDevice]; - - self.progressView.hidden = NO; - self.progressView.layer.cornerRadius = 20; - self.progressView.clipsToBounds = true; - [self.indicator startAnimating]; - } else { - // viewDidLoadの時点ではデバイスを認識できておらずその後認識された場合は、ボタンがタップされたタイミングでConnectedと表示する - self.ssidLabel.text = @"Sony Camera Connected."; - } + [self confirmOpenWiFiSettings]; } #pragma mark - SonyCameraDevicePluginDelegate delegate methods @@ -82,19 +95,17 @@ - (IBAction) searchBtnDidPushed:(id)sender - (void) didReceiveDeviceList:(BOOL) discovery { if (discovery) { - CFArrayRef interfaces = CNCopySupportedInterfaces(); - CFDictionaryRef dicRef = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(interfaces, 0)); - if (dicRef) { - NSString *ssid = CFDictionaryGetValue(dicRef, kCNNetworkInfoKeySSID); - self.ssidLabel.text = ssid; - self.ssidLabel.text = @"Sony Camera Connected."; - } + self.ssidLabel.text = @"Sony Camera Connected."; } else { - // 発見できず self.ssidLabel.text = @"Not Found Sony Camera."; } self.progressView.hidden = YES; [self.indicator stopAnimating]; } +- (void) didReceiveUpdateDevice +{ + [self checkConnectSonyCamera]; +} + @end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraSimpleHttpServer.h b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraSimpleHttpServer.h new file mode 100644 index 00000000..21b435ce --- /dev/null +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraSimpleHttpServer.h @@ -0,0 +1,56 @@ +// +// SonyCameraSimpleHttpServer.h +// dConnectDeviceSonyCamera +// +// Copyright (c) 2017 NTT DOCOMO, INC. +// Released under the MIT license +// http://opensource.org/licenses/mit-license.php +// + +#import + + +/*! + @brief Sonyカメラからの画像を配信するための簡易サーバ. + */ +@interface SonyCameraSimpleHttpServer : NSObject + +/*! + @brief ポート番号 + */ +@property (nonatomic) NSInteger listenPort; + +/*! + @brief プレビューを送信するためのタイムスライス. + */ +@property (nonatomic) NSInteger timeSlice; + +/*! + @brief サーバを起動します. + + @retval YSE サーバの起動に成功 + @retval NO サーバの起動に失敗 + */ +- (BOOL) start; + +/*! + @brief サーバを停止します. + */ +- (void) stop; + +/*! + @brief サーバのURLを取得します. + + @retval サーバのURL + */ +- (NSString *) getUrl; + + +/*! + @brief 配信する画像を設定します. + + @param[in] data 画像データ + */ +- (void) offerData:(NSData *)data; + +@end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraSimpleHttpServer.m b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraSimpleHttpServer.m new file mode 100644 index 00000000..77a0ee56 --- /dev/null +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/SonyCameraSimpleHttpServer.m @@ -0,0 +1,272 @@ +// +// SonyCameraSimpleHttpServer.m +// dConnectDeviceSonyCamera +// +// Copyright (c) 2017 NTT DOCOMO, INC. +// Released under the MIT license +// http://opensource.org/licenses/mit-license.php +// + +#import "SonyCameraSimpleHttpServer.h" +#import "GCDAsyncSocket.h" +#import + + +// HTTP通信のタイムアウトを定義 +#define HTTP_TIMEOUT 3.0 + + +/*! + @brief 現在時刻をミリ秒で取得します. + @retval 現在時刻 + */ +static uint64_t getUptimeInMilliseconds() +{ + const int64_t kOneMillion = 1000 * 1000; + static mach_timebase_info_data_t s_timebase_info; + + if (s_timebase_info.denom == 0) { + (void) mach_timebase_info(&s_timebase_info); + } + + // mach_absolute_time() returns billionth of seconds, + // so divide by one million to get milliseconds + return ((mach_absolute_time() * s_timebase_info.numer) / (kOneMillion * s_timebase_info.denom)); +} + + +#pragma mark - SonyCameraConnection + + +@interface SonyCameraConnection : NSObject + +@property (nonatomic, strong) GCDAsyncSocket *fromSocket; +@property (nonatomic) BOOL ready; +@property (nonatomic) uint64_t startTime; + +@end + + +@implementation SonyCameraConnection + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.fromSocket = nil; + self.ready = NO; + self.startTime = 0; + } + return self; +} + +@end + + +#pragma mark - SonyCameraSimpleHttpServer + + +@interface SonyCameraSimpleHttpServer () + +@end + + +@implementation SonyCameraSimpleHttpServer { + GCDAsyncSocket *_listenSocket; + NSMutableArray *_connections; + NSString *_boundary; + NSString *_path; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.listenPort = 8080; + self.timeSlice = 100; + + _listenSocket = nil; + _connections = [NSMutableArray array]; + _boundary = @"0123456789ABCDEF"; + _path = [[NSUUID UUID] UUIDString]; + } + return self; +} + + +#pragma mark - GCDAsyncSocketDelegate Methods + +- (void)socket:(GCDAsyncSocket *)sock didAcceptNewSocket:(GCDAsyncSocket *)newSocket +{ + SonyCameraConnection *connection = [SonyCameraConnection new]; + connection.fromSocket = newSocket; + connection.ready = NO; + + @synchronized(self) { + [_connections addObject:connection]; + } + + [newSocket readDataWithTimeout:HTTP_TIMEOUT tag:0]; +} + +- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err +{ + @synchronized(self) { + SonyCameraConnection *connection = [self foundConnection:sock]; + if (connection) { + [_connections removeObject:connection]; + } + } +} + +- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag +{ + NSString *headerData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + if ([self parseHttpHeader:headerData]) { + [self writeHeadersToSocket:sock]; + } else { + [sock disconnect]; + } +} + +#pragma mark - Private Methods + +- (BOOL) parseHttpHeader:(NSString *)header +{ + NSString *method; + NSString *path; + NSMutableDictionary *headers = [NSMutableDictionary dictionary]; + NSArray* lines = [header componentsSeparatedByString:@"\r\n"]; + int lineIndex = 0; + + if (lines.count == 0) { + return NO; + } + + NSArray *keyValue = [lines[0] componentsSeparatedByString:@" "]; + if (keyValue && keyValue.count >= 2) { + method = [keyValue[0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + path = [keyValue[1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + } + + if (!method || !path) { + return NO; + } + + if (![[method lowercaseString] isEqualToString:@"get"]) { + return NO; + } + + if (![[path substringFromIndex:1] isEqualToString:_path]) { + return NO; + } + + // 各ヘッダーを格納 + for (; lineIndex < lines.count; lineIndex++) { + NSString *line = lines[lineIndex]; + NSArray *keyValue = [line componentsSeparatedByString:@":"]; + if (keyValue && keyValue.count == 2) { + NSString *key =[keyValue[0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + NSString *value = [keyValue[1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + headers[key] = value; + } + } + + return YES; +} + +- (void) writeHeadersToSocket:(GCDAsyncSocket *)socket +{ + NSString *str = @"HTTP/1.0 200 OK\r\n" + "Server: SonyCameraSimpleHttpServer\r\n" + "Connection: close\r\n" + "Max-Age: 0\r\n" + "Expires: 0\r\n" + "Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n" + "Pragma: no-cache\r\n" + "Content-Type: multipart/x-mixed-replace; boundary=%@\r\n" + "\r\n" + "--%@\r\n"; + + NSString *string = [NSString stringWithFormat:str, _boundary, _boundary]; + NSData *headerData = [string dataUsingEncoding:NSUTF8StringEncoding]; + [socket writeData:headerData withTimeout:HTTP_TIMEOUT tag:0]; + + SonyCameraConnection *conn = [self foundConnection:socket]; + if (conn) { + conn.ready = YES; + } +} + +- (void) sendImageData:(NSData *)imageData toSocket:(GCDAsyncSocket *)socket +{ + NSString *str = @"--%@\r\n" + "Content-Type: %@\r\n" + "Content-Length: %d\r\n" + "\r\n"; + NSString *string = [NSString stringWithFormat:str, _boundary, @"image/jpg", imageData.length]; + NSData *headerData = [string dataUsingEncoding:NSUTF8StringEncoding]; + NSData *endData = [@"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]; + [socket writeData:headerData withTimeout:HTTP_TIMEOUT tag:0]; + [socket writeData:imageData withTimeout:HTTP_TIMEOUT tag:0]; + [socket writeData:endData withTimeout:HTTP_TIMEOUT tag:0]; +} + +- (SonyCameraConnection *) foundConnection:(GCDAsyncSocket *)socket +{ + __block SonyCameraConnection *result = nil; + + [_connections enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(SonyCameraConnection *connection, NSUInteger idx, BOOL *stop) { + if ([connection.fromSocket.description isEqualToString:socket.description]) { + result = connection; + *stop = YES; + } + }]; + + return result; +} + + +#pragma mark - Public Methods + +- (BOOL) start +{ + NSError *error = nil; + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + _listenSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:queue]; + [_listenSocket acceptOnPort:self.listenPort error:&error]; + if (error) { + DCLogInfo(@"Failed to start a server. error=%@", error); + [self stop]; + return NO; + } + return YES; +} + +- (void) stop +{ + [_listenSocket setDelegate:nil delegateQueue:NULL]; + [_listenSocket disconnect]; + _listenSocket = nil; +} + +- (NSString *) getUrl +{ + NSString *str = @"http://localhost:%d/%@"; + return [NSString stringWithFormat:str, self.listenPort, _path]; +} + +- (void) offerData:(NSData *)data +{ + __block typeof(self) weakSelf = self; + + [_connections enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(SonyCameraConnection *connection, NSUInteger idx, BOOL *stop) { + uint64_t elapsed = getUptimeInMilliseconds() - connection.startTime; + if (connection.ready && elapsed > weakSelf.timeSlice) { + [weakSelf sendImageData:data toSocket:connection.fromSocket]; + connection.startTime = getUptimeInMilliseconds(); + } + }]; +} + +@end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraCameraProfile.m b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraCameraProfile.m index 11a3e18c..62c1013a 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraCameraProfile.m +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraCameraProfile.m @@ -24,94 +24,88 @@ - (NSString *) profileName { } - (instancetype) init { - self = [super init]; if (self) { - + __weak typeof(self) weakSelf = self; + // API登録(didReceiveGetZoomRequest相当) NSString *getZoomRequestApiPath = [self apiPath: nil attributeName: SonyCameraCameraProfileAttrZoom]; [self addGetPath: getZoomRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - NSString *serviceId = [request serviceId]; - - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - - // サービスIDのチェック - if (![manager selectServiceId:serviceId response:response]) { - return YES; - } - - // サポートしていない - if (![manager.remoteApi isApiAvailable:API_actZoom]) { - [response setErrorToNotSupportAttribute]; - return YES; - } - - if (manager.remoteApi.zoomPosition < 0) { - [response setErrorToIllegalDeviceState]; - } else { - // ズームのデータ - [response setResult:DConnectMessageResultTypeOk]; - [response setDouble:manager.remoteApi.zoomPosition - forKey:SonyCameraCameraProfileParamZoomdiameter]; - } - return YES; + return [weakSelf didReceiveGetZoomRequest:request response:response]; }]; // API登録(didReceivePutZoomRequest相当) NSString *putZoomRequestApiPath = [self apiPath: nil attributeName: SonyCameraCameraProfileAttrZoom]; [self addPutPath: putZoomRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - NSString *serviceId = [request serviceId]; - NSString *direction = [request stringForKey:SonyCameraCameraProfileParamDirection]; - NSString *movement = [request stringForKey:SonyCameraCameraProfileParamMovement]; - - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - - // サービスIDのチェック - if (![manager selectServiceId:serviceId response:response]) { - return YES; - } - - // サポートしていない - if (![manager.remoteApi isApiAvailable:API_actZoom]) { - [response setErrorToNotSupportAttribute]; - return YES; - } - - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSDictionary *dict = [manager.remoteApi actZoom:direction movement:movement]; - if (dict == nil) { - [response setErrorToTimeout]; - } else { - NSString *errorMessage = @""; - NSInteger errorCode = -1; - NSArray *resultArray = dict[@"result"]; - NSArray *errorArray = dict[@"error"]; - if (errorArray && errorArray.count > 0) { - errorCode = (NSInteger) errorArray[0]; - errorMessage = errorArray[1]; - } - - // レスポンス作成 - if (resultArray.count <= 0 && errorCode >= 0) { - [response setErrorToInvalidRequestParameter]; - } else { - [response setResult:DConnectMessageResultTypeOk]; - } - } - - // レスポンスを返却 - [[DConnectManager sharedManager] sendResponse:response]; - }); - - // レスポンスは非同期で返却するので - return NO; + return [weakSelf didReceivePutZoomRequest:request response:response]; }]; } return self; } +#pragma mark - Private Methods - + +-(BOOL) didReceiveGetZoomRequest:(DConnectRequestMessage *)request response:(DConnectResponseMessage *)response +{ + SonyCameraDevicePlugin *plugin = (SonyCameraDevicePlugin *)self.plugin; + SonyCameraManager *manager = plugin.sonyCameraManager; + NSString *serviceId = [request serviceId]; + + // サービスIDのチェック + if (![manager isConnectedService:serviceId]) { + [response setErrorToIllegalDeviceStateWithMessage:@"Sony's camera is not ready."]; + return YES; + } + + // サポートしていない + if (![manager isSupportedZoom]) { + [response setErrorToNotSupportAttribute]; + return YES; + } + + double zoom = [manager getZoom]; + if (zoom < 0) { + [response setErrorToIllegalDeviceState]; + } else { + [response setResult:DConnectMessageResultTypeOk]; + [response setDouble:zoom forKey:SonyCameraCameraProfileParamZoomdiameter]; + } + return YES; +} + +- (BOOL) didReceivePutZoomRequest:(DConnectRequestMessage *)request response:(DConnectResponseMessage *)response +{ + SonyCameraDevicePlugin *plugin = (SonyCameraDevicePlugin *)self.plugin; + SonyCameraManager *manager = plugin.sonyCameraManager; + NSString *serviceId = [request serviceId]; + NSString *direction = [request stringForKey:SonyCameraCameraProfileParamDirection]; + NSString *movement = [request stringForKey:SonyCameraCameraProfileParamMovement]; + + // サービスIDのチェック + if (![manager isConnectedService:serviceId]) { + [response setErrorToIllegalDeviceStateWithMessage:@"Sony's camera is not ready."]; + return YES; + } + + // サポートしていない + if (![manager isSupportedZoom]) { + [response setErrorToNotSupportAttribute]; + return YES; + } + + [manager setZoomByDirection:direction movement:movement block:^(int errorCode, NSString *errorMessage) { + if (errorCode == 0) { + [response setResult:DConnectMessageResultTypeOk]; + } else { + [response setErrorToInvalidRequestParameter]; + } + [[DConnectManager sharedManager] sendResponse:response]; + }]; + + // レスポンスは非同期で返却するので + return NO; +} + @end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraMediaStreamRecordingProfile.h b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraMediaStreamRecordingProfile.h index fd817d34..603315fd 100644 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraMediaStreamRecordingProfile.h +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraMediaStreamRecordingProfile.h @@ -13,6 +13,6 @@ @interface SonyCameraMediaStreamRecordingProfile : DConnectMediaStreamRecordingProfile -- (instancetype) initWithLiveViewDelegate: (id) liveViewDelegate remoteApiUtilDelegate:(id) remoteApiUtilDelegate; +- (instancetype) init; @end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraMediaStreamRecordingProfile.m b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraMediaStreamRecordingProfile.m index 84531acf..09ac55a9 100644 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraMediaStreamRecordingProfile.m +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraMediaStreamRecordingProfile.m @@ -8,467 +8,385 @@ // #import "SonyCameraMediaStreamRecordingProfile.h" +#import "SonyCameraDevicePlugin.h" #import "SonyCameraManager.h" #import "RemoteApiList.h" -@interface SonyCameraMediaStreamRecordingProfile() +/*! + @brief ターゲットIDを定義. + */ +#define SONY_TARGET_ID @"sonycamera" -@property(nonatomic, weak) id mLiveViewDelegate; -@property(nonatomic, weak) id mRemoteApiUtilDelegate; - -@end +/*! + @brief ターゲット名を定義. + */ +#define SONY_TARGET_NAME @"Sony Camera" @implementation SonyCameraMediaStreamRecordingProfile -- (instancetype) initWithLiveViewDelegate: (id) liveViewDelegate remoteApiUtilDelegate:(id) remoteApiUtilDelegate { +- (instancetype) init { self = [super init]; if (self) { - _mLiveViewDelegate = liveViewDelegate; - _mRemoteApiUtilDelegate = remoteApiUtilDelegate; - - __weak SonyCameraMediaStreamRecordingProfile *weakSelf = self; + __weak typeof(self) weakSelf = self; - // API登録(didReceiveGetMediaRecorderRequest相当) + // GET /mediaStreamRecording/mediaRecorder NSString *getMediaRecorderRequestApiPath = [self apiPath: nil attributeName: DConnectMediaStreamRecordingProfileAttrMediaRecorder]; [self addGetPath: getMediaRecorderRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - NSString *serviceId = [request serviceId]; - - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - - // サービスIDのチェック - if (![manager selectServiceId:serviceId response:response]) { - return YES; - } - - // サポートしていない - if (![manager.remoteApi isApiAvailable:API_getStillSize]) { - [response setErrorToNotSupportAttribute]; - return YES; - } - - // MEMO: getStillSizeは、QX10は最新のファームウェアでないとサポートしていない - NSDictionary *dic = [manager.remoteApi getStillSize]; - if (dic) { - NSString *aspect = dic[@"aspect"]; - NSString *size = dic[@"size"]; - - NSArray *sizes = [aspect componentsSeparatedByString:@":"]; - NSString *widthString = sizes[0]; - NSString *heightString = sizes[1]; - int stillSize = 0; - int width = [widthString intValue]; - int height = [heightString intValue]; - - if ([aspect isEqualToString:@"1:1"]) { - if ([size isEqualToString:@"3.7M"]) { - stillSize = (1920 * 1920) / (width * height); - } else if ([size isEqualToString:@"13M"]) { - stillSize = (3648 * 3648) / (width * height); - } - } else if ([aspect isEqualToString:@"3:2"]) { - if ([size isEqualToString:@"20M"]) { - stillSize = (5472 * 3648) / (width * height); - } else if ([size isEqualToString:@"5M"]) { - stillSize = (2736 * 1824) / (width * height); - } - } else if ([aspect isEqualToString:@"4:3"]) { - if ([size isEqualToString:@"18M"]) { - stillSize = (4864 * 3648) / (width * height); - } else if ([size isEqualToString:@"5M"]) { - stillSize = (2592 * 1944) / (width * height); - } - } else if ([aspect isEqualToString:@"16:9"]) { - if ([size isEqualToString:@"17M"]) { - stillSize = (5472 * 3080) / (width * height); - } else if ([size isEqualToString:@"4.2M"]) { - stillSize = (2720 * 1528) / (width * height); - } - } - - if (stillSize == 0) { - [response setErrorToNotSupportAttribute]; - } else { - NSString *cameraStatus = manager.remoteApi.cameraStatus; - NSString *status = nil; - if ([cameraStatus isEqualToString:@"Error"] || - [cameraStatus isEqualToString:@"NotReady"] || - [cameraStatus isEqualToString:@"MovieSaving"] || - [cameraStatus isEqualToString:@"AudioSaving"] || - [cameraStatus isEqualToString:@"StillSaving"]) { - status = DConnectMediaStreamRecordingProfileRecorderStateInactive; - } else if ([cameraStatus isEqualToString:@"StillCapturing"] || - [cameraStatus isEqualToString:@"MediaRecording"] || - [cameraStatus isEqualToString:@"AudioRecording"] || - [cameraStatus isEqualToString:@"IntervalRecording"]) { - status = DConnectMediaStreamRecordingProfileRecorderStateRecording; - } else if ([cameraStatus isEqualToString:@"MovieWaitRecStart"] || - [cameraStatus isEqualToString:@"MoviewWaitRecStop"] || - [cameraStatus isEqualToString:@"AudioWaitRecStart"] || - [cameraStatus isEqualToString:@"AudioRecWaitRecStop"] || - [cameraStatus isEqualToString:@"IntervalWaitRecStart"] || - [cameraStatus isEqualToString:@"IntervalWaitRecStop"]) { - status = DConnectMediaStreamRecordingProfileRecorderStatePaused; - } - - width = width * stillSize; - height = height * stillSize; - - DConnectMessage *recorder = [DConnectMessage message]; - [DConnectMediaStreamRecordingProfile setRecorderId:SERVICE_ID target:recorder]; - [DConnectMediaStreamRecordingProfile setRecorderId:@"SonyCamera" target:recorder]; - [DConnectMediaStreamRecordingProfile setRecorderName:@"SonyCamera" target:recorder]; - [DConnectMediaStreamRecordingProfile setRecorderState:status target:recorder]; - [DConnectMediaStreamRecordingProfile setRecorderMIMEType:@"image/png" target:recorder]; - [DConnectMediaStreamRecordingProfile setRecorderImageWidth:width target:recorder]; - [DConnectMediaStreamRecordingProfile setRecorderImageHeight:height target:recorder]; - [DConnectMediaStreamRecordingProfile setRecorderConfig:@"" target:recorder]; - - DConnectArray *recorders = [DConnectArray array]; - [recorders addMessage:recorder]; - - [response setResult:DConnectMessageResultTypeOk]; - [DConnectMediaStreamRecordingProfile setRecorders:recorders target:response]; - } - } else { - [response setErrorToNotSupportAttribute]; - } - return YES; + return [weakSelf didReceivedGetMediaRecorderRequest:request response:response]; }]; - // API登録(didReceivePostTakePhotoRequest相当) + // POST /mediaStreamRecording/takePhoto NSString *postTakePhotoRequestApiPath = [self apiPath: nil attributeName: DConnectMediaStreamRecordingProfileAttrTakePhoto]; [self addPostPath: postTakePhotoRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - NSString *serviceId = [request serviceId]; - NSString *target = [DConnectMediaStreamRecordingProfile targetFromRequest:request]; - - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - - // サービスIDのチェック - if (![manager selectServiceId:serviceId response:response]) { - return YES; - } - - // サポートしていない - if (![manager.remoteApi isApiAvailable:API_actTakePicture]) { - [response setErrorToNotSupportAttribute]; - return YES; - } - - // 既に撮影中はエラー - if ([SonyCameraStatusMovieRecording isEqualToString:manager.remoteApi.cameraStatus]) { - [response setErrorToIllegalDeviceState]; - return YES; - } - - // 動画撮影モード切り替え - if (![SonyCameraShootModePicture isEqualToString:manager.remoteApi.shootMode] - && ![manager.remoteApi actSetShootMode:SonyCameraShootModePicture]) { - [response setErrorToIllegalDeviceState]; - return YES; - } - - if (target && ![target isEqualToString:@"SonyCamera"]) { - [response setErrorToInvalidRequestParameter]; - return YES; - } - - // 写真撮影をバックグランドでAPIなどを実行 - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSDictionary *dict = [manager.remoteApi actTakePicture]; - if (dict == nil) { - [response setErrorToTimeout]; - } else { - NSString *errorMessage = @""; - NSInteger errorCode = -1; - NSArray *resultArray = dict[@"result"]; - NSArray *errorArray = dict[@"error"]; - if (errorArray && errorArray.count > 0) { - errorCode = (NSInteger) errorArray[0]; - errorMessage = errorArray[1]; - } - - // レスポンス作成 - if (resultArray.count <= 0 && errorCode >= 0) { - [response setErrorToUnknown]; - } else { - NSArray *arr = resultArray[0]; - NSData *data = [manager download:arr[0]]; - if (data) { - // ファイルを保存 - NSString *uri = [manager saveFile:data]; - [[weakSelf mRemoteApiUtilDelegate] didReceivedImage:uri]; - if (!uri) { - // ファイル保存に失敗 - [response setErrorToUnknown]; - } else { - [response setResult:DConnectMessageResultTypeOk]; - [DConnectMediaStreamRecordingProfile setPath:[uri lastPathComponent] target:response]; - [DConnectMediaStreamRecordingProfile setUri:uri target:response]; - } - } else { - [response setErrorToUnknown]; - } - } - } - - // レスポンスを返却 - [[DConnectManager sharedManager] sendResponse:response]; - }); - - return NO; + return [weakSelf didReceivePostTakePhotoRequest:request response:response]; }]; - // API登録(didReceivePostRecordRequest相当) + // POST /mediaStreamRecording/record NSString *postRecordRequestApiPath = [self apiPath: nil attributeName: DConnectMediaStreamRecordingProfileAttrRecord]; [self addPostPath: postRecordRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - NSString *serviceId = [request serviceId]; - - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - - // サービスIDのチェック - if (![manager selectServiceId:serviceId response:response]) { - return YES; - } - - // サポートしていない - if (![manager.remoteApi isApiAvailable:API_startRecMode]) { - [response setErrorToNotSupportAttribute]; - return YES; - } - - // 撮影中は、さらに撮影できないのでエラーを返す - if ([SonyCameraStatusMovieRecording isEqualToString:manager.remoteApi.cameraStatus]) { - [response setErrorToIllegalDeviceState]; - return YES; - } - - // 動画撮影モード切り替え - if (![SonyCameraShootModeMovie isEqualToString:manager.remoteApi.shootMode] - && ![manager.remoteApi actSetShootMode:SonyCameraShootModeMovie]) { - [response setErrorToIllegalDeviceState]; - return YES; - } - - // 撮影開始 - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSDictionary *dict = [manager.remoteApi startMovieRec]; - if (dict) { - [response setResult:DConnectMessageResultTypeOk]; - } else { - [response setErrorToUnknown]; - } - // レスポンスを返却 - [[DConnectManager sharedManager] sendResponse:response]; - }); - - return NO; + return [weakSelf didReceivePostRecordRequest:request response:response]; }]; - // API登録(didReceivePutStopRequest相当) + // PUT /mediaStreamRecording/stop NSString *putStopRequestApiPath = [self apiPath: nil attributeName: DConnectMediaStreamRecordingProfileAttrStop]; [self addPutPath: putStopRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - NSString *serviceId = [request serviceId]; - - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - - // サービスIDのチェック - if (![manager selectServiceId:serviceId response:response]) { - return YES; - } - - // 撮影が開始されていないので、エラーを返す。 - if ([SonyCameraStatusIdle isEqualToString:manager.remoteApi.cameraStatus]) { - [response setErrorToIllegalDeviceState]; - return YES; - } - - // サポートしていない - if (![manager.remoteApi isApiAvailable:API_stopRecMode]) { - [response setErrorToNotSupportAttribute]; - return YES; - } - - // 撮影停止 - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSDictionary *dict = [manager.remoteApi stopMovieRec]; - if (dict) { - [response setResult:DConnectMessageResultTypeOk]; - } else { - [response setErrorToUnknown]; - } - // レスポンスを返却 - [[DConnectManager sharedManager] sendResponse:response]; - }); - - return NO; + return [weakSelf didReceivePutStopRequest:request response:response]; }]; - // API登録(didReceivePutOnPhotoRequest相当) + // PUT /mediaStreamRecording/onPhoto NSString *putOnPhotoRequestApiPath = [self apiPath: nil attributeName: DConnectMediaStreamRecordingProfileAttrOnPhoto]; [self addPutPath: putOnPhotoRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - NSString *serviceId = [request serviceId]; - NSString *origin = [request origin]; - - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - - // サービスIDのチェック - if (![manager selectServiceId:serviceId response:response]) { - return YES; - } - - // オリジン確認 - if (!origin) { - [response setErrorToInvalidRequestParameterWithMessage:@"origin is nil."]; - return YES; - } - - DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[weakSelf.plugin class]]; - DConnectEventError error = [mgr addEventForRequest:request]; - if (error == DConnectEventErrorNone) { - [response setResult:DConnectMessageResultTypeOk]; - } else if (error == DConnectEventErrorInvalidParameter) { - [response setErrorToInvalidRequestParameter]; - } else { - [response setErrorToUnknown]; - } - return YES; + return [weakSelf didReceivePutOnPhotoRequest:request response:response]; }]; - // API登録(didReceiveDeleteOnPhotoRequest相当) + // DELETE /mediaStreamRecording/onPhoto NSString *deleteOnPhotoRequestApiPath = [self apiPath: nil attributeName: DConnectMediaStreamRecordingProfileAttrOnPhoto]; [self addDeletePath: deleteOnPhotoRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - NSString *serviceId = [request serviceId]; - NSString *origin = [request origin]; - - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - - // サービスIDのチェック - if (![manager selectServiceId:serviceId response:response]) { - return YES; - } - - // オリジン確認 - if (!origin) { - [response setErrorToInvalidRequestParameterWithMessage:@"origin is nil."]; - return YES; - } - - DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[weakSelf.plugin class]]; - DConnectEventError error = [mgr removeEventForRequest:request]; - if (error == DConnectEventErrorNone) { - [response setResult:DConnectMessageResultTypeOk]; - } else if (error == DConnectEventErrorInvalidParameter - || error == DConnectEventErrorNotFound) { - [response setErrorToInvalidRequestParameter]; - } else { - [response setErrorToUnknown]; - } - return YES; + return [weakSelf didReceiveDeleteOnPhotoRequest:request response:response]; }]; - // API登録(didReceivePutOnDataAvailableRequest相当) - NSString *putOnDataAvailableRequestApiPath = [self apiPath: nil - attributeName: DConnectMediaStreamRecordingProfileAttrOnDataAvailable]; - [self addPutPath: putOnDataAvailableRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - NSString *serviceId = [request serviceId]; - NSString *origin = [request origin]; - - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - - // サービスIDのチェック - if (![manager selectServiceId:serviceId response:response]) { - return YES; - } - - // オリジン確認 - if (!origin) { - [response setErrorToInvalidRequestParameterWithMessage:@"origin is nil."]; - return YES; - } - - // サポートしていない - if (![manager.remoteApi isApiAvailable:API_startLiveview]) { - [response setErrorToNotSupportAttribute]; - return YES; - } - - DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[weakSelf.plugin class]]; - DConnectEventError error = [mgr addEventForRequest:request]; - if (error == DConnectEventErrorNone) { - [response setResult:DConnectMessageResultTypeOk]; - // プレビュー開始 - if (![manager.remoteApi isStartedLiveView]) { - [manager.remoteApi actStartLiveView:[weakSelf mLiveViewDelegate]]; - } - } else if (error == DConnectEventErrorInvalidParameter) { - [response setErrorToInvalidRequestParameter]; - } else { - [response setErrorToUnknown]; - } - return YES; + // PUT /mediaStreamRecording/preview + NSString *putPreviewRequestApiPath = [self apiPath: nil + attributeName: @"preview"]; + [self addPutPath: putPreviewRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { + return [weakSelf didReceivePutPreviewRequest:request response:response]; }]; - // API登録(didReceiveDeleteOnDataAvailableRequest相当) - NSString *deleteOnDataAvailableRequestApiPath = [self apiPath: nil - attributeName: DConnectMediaStreamRecordingProfileAttrOnDataAvailable]; - [self addDeletePath: deleteOnDataAvailableRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - NSString *serviceId = [request serviceId]; - NSString *origin = [request origin]; - - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - - // サービスIDのチェック - if (![manager selectServiceId:serviceId response:response]) { - return YES; - } - - // オリジン確認 - if (!origin) { - [response setErrorToInvalidRequestParameterWithMessage:@"origin is nil."]; - return YES; - } - - // サポートしていない - if (![manager.remoteApi isApiAvailable:API_startLiveview]) { - [response setErrorToNotSupportAttribute]; - return YES; - } - - DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[weakSelf.plugin class]]; - DConnectEventError error = [mgr removeEventForRequest:request]; - if (error == DConnectEventErrorNone) { - [response setResult:DConnectMessageResultTypeOk]; - - // プレビュー停止 - if ([manager.remoteApi isStartedLiveView] && ![manager hasDataAvaiableEvent]) { - [manager.remoteApi actStopLiveView]; - } - } else if (error == DConnectEventErrorInvalidParameter - && error == DConnectEventErrorNotFound) { - [response setErrorToInvalidRequestParameter]; - } else { - [response setErrorToUnknown]; - } - return YES; + // DELETE /mediaStreamRecording/preview + NSString *deletePreviewRequestApiPath = [self apiPath: nil + attributeName: @"preview"]; + [self addDeletePath: deletePreviewRequestApiPath api: ^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { + return [weakSelf didReceiveDeletePreviewRequest:request response:response]; }]; - } return self; } +#pragma mark - Private Methods + +- (BOOL) didReceivedGetMediaRecorderRequest:(DConnectRequestMessage *)request response:(DConnectResponseMessage *)response +{ + SonyCameraDevicePlugin *plugin = (SonyCameraDevicePlugin *)self.plugin; + SonyCameraManager *manager = plugin.sonyCameraManager; + NSString *serviceId = [request serviceId]; + + // サービスIDのチェック + if (![manager isConnectedService:serviceId]) { + [response setErrorToIllegalDeviceStateWithMessage:@"Sony's camera is not ready."]; + return YES; + } + + [manager getCameraState:^(NSString *state, int width, int height) { + if (state) { + DConnectMessage *recorder = [DConnectMessage message]; + [DConnectMediaStreamRecordingProfile setRecorderId:SONY_TARGET_ID target:recorder]; + [DConnectMediaStreamRecordingProfile setRecorderName:SONY_TARGET_NAME target:recorder]; + [DConnectMediaStreamRecordingProfile setRecorderState:state target:recorder]; + [DConnectMediaStreamRecordingProfile setRecorderMIMEType:@"image/jpg" target:recorder]; + if (width > 0 && height > 0) { + [DConnectMediaStreamRecordingProfile setRecorderImageWidth:width target:recorder]; + [DConnectMediaStreamRecordingProfile setRecorderImageHeight:height target:recorder]; + } + + DConnectArray *recorders = [DConnectArray array]; + [recorders addMessage:recorder]; + + [response setResult:DConnectMessageResultTypeOk]; + [DConnectMediaStreamRecordingProfile setRecorders:recorders target:response]; + } else { + [response setErrorToNotSupportAttribute]; + } + [[DConnectManager sharedManager] sendResponse:response]; + }]; + return NO; +} + + +- (BOOL) didReceivePostTakePhotoRequest:(DConnectRequestMessage *)request response:(DConnectResponseMessage *)response +{ + SonyCameraDevicePlugin *plugin = (SonyCameraDevicePlugin *)self.plugin; + SonyCameraManager *manager = plugin.sonyCameraManager; + NSString *serviceId = [request serviceId]; + NSString *target = [DConnectMediaStreamRecordingProfile targetFromRequest:request]; + + // サービスIDのチェック + if (![manager isConnectedService:serviceId]) { + [response setErrorToIllegalDeviceStateWithMessage:@"Sony's camera is not ready."]; + return YES; + } + + // ターゲットチェック + if (target && ![target isEqualToString:SONY_TARGET_ID]) { + [response setErrorToInvalidRequestParameterWithMessage:@"target is invalid."]; + return YES; + } + + // サポートしていない + if (![manager isSupportedPicture]) { + [response setErrorToNotSupportAttribute]; + return YES; + } + + // 既に撮影中はエラー + if ([manager isRecording]) { + [response setErrorToIllegalDeviceState]; + return YES; + } + + [manager takePicture:^(NSString *uri) { + if (uri) { + [response setResult:DConnectMessageResultTypeOk]; + [DConnectMediaStreamRecordingProfile setUri:uri target:response]; + } else { + [response setErrorToUnknown]; + } + [[DConnectManager sharedManager] sendResponse:response]; + }]; + + return NO; +} + + +- (BOOL) didReceivePostRecordRequest:(DConnectRequestMessage *)request response:(DConnectResponseMessage *)response +{ + SonyCameraDevicePlugin *plugin = (SonyCameraDevicePlugin *)self.plugin; + SonyCameraManager *manager = plugin.sonyCameraManager; + NSString *serviceId = [request serviceId]; + NSString *target = [DConnectMediaStreamRecordingProfile targetFromRequest:request]; + + // サービスIDのチェック + if (![manager isConnectedService:serviceId]) { + [response setErrorToIllegalDeviceStateWithMessage:@"Sony's camera is not ready."]; + return YES; + } + + // ターゲットチェック + if (target && ![target isEqualToString:SONY_TARGET_ID]) { + [response setErrorToInvalidRequestParameterWithMessage:@"target is invalid."]; + return YES; + } + + // サポートしていない + if (![manager isSupportedRecording]) { + [response setErrorToNotSupportAttribute]; + return YES; + } + + // 撮影中は、さらに撮影できないのでエラーを返す + if ([manager isRecording]) { + [response setErrorToIllegalDeviceState]; + return YES; + } + + [manager startMovieRec:^(int errorCode, NSString *errorMessage) { + if (errorCode == 0) { + [response setResult:DConnectMessageResultTypeOk]; + } else { + [response setError:errorCode message:errorMessage]; + } + [[DConnectManager sharedManager] sendResponse:response]; + }]; + + return NO; +} + + +- (BOOL) didReceivePutStopRequest:(DConnectRequestMessage *)request response:(DConnectResponseMessage *)response +{ + SonyCameraDevicePlugin *plugin = (SonyCameraDevicePlugin *)self.plugin; + SonyCameraManager *manager = plugin.sonyCameraManager; + NSString *serviceId = [request serviceId]; + NSString *target = [DConnectMediaStreamRecordingProfile targetFromRequest:request]; + + // サービスIDのチェック + if (![manager isConnectedService:serviceId]) { + [response setErrorToIllegalDeviceStateWithMessage:@"Sony's camera is not ready."]; + return YES; + } + + // ターゲットチェック + if (target && ![target isEqualToString:SONY_TARGET_ID]) { + [response setErrorToInvalidRequestParameterWithMessage:@"target is invalid."]; + return YES; + } + + // サポートしていない + if (![manager isSupportedRecording]) { + [response setErrorToNotSupportAttribute]; + return YES; + } + + // 撮影が開始されていないので、エラーを返す。 + if (![manager isRecording]) { + [response setErrorToIllegalDeviceState]; + return YES; + } + + [manager stopMovieRec:^(int errorCode, NSString *errorMessage) { + if (errorCode == 0) { + [response setResult:DConnectMessageResultTypeOk]; + } else { + [response setError:errorCode message:errorMessage]; + } + [[DConnectManager sharedManager] sendResponse:response]; + }]; + + return NO; +} + +- (BOOL) didReceivePutOnPhotoRequest:(DConnectRequestMessage *)request response:(DConnectResponseMessage *)response +{ + SonyCameraDevicePlugin *plugin = (SonyCameraDevicePlugin *)self.plugin; + SonyCameraManager *manager = plugin.sonyCameraManager; + NSString *serviceId = [request serviceId]; + NSString *target = [DConnectMediaStreamRecordingProfile targetFromRequest:request]; + + // サービスIDのチェック + if (![manager isConnectedService:serviceId]) { + [response setErrorToIllegalDeviceStateWithMessage:@"Sony's camera is not ready."]; + return YES; + } + + // ターゲットチェック + if (target && ![target isEqualToString:SONY_TARGET_ID]) { + [response setErrorToInvalidRequestParameterWithMessage:@"target is invalid."]; + return YES; + } + + DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[self.plugin class]]; + DConnectEventError error = [mgr addEventForRequest:request]; + if (error == DConnectEventErrorNone) { + [response setResult:DConnectMessageResultTypeOk]; + } else if (error == DConnectEventErrorInvalidParameter) { + [response setErrorToInvalidRequestParameter]; + } else { + [response setErrorToUnknown]; + } + return YES; +} + +- (BOOL) didReceiveDeleteOnPhotoRequest:(DConnectRequestMessage *)request response:(DConnectResponseMessage *)response +{ + SonyCameraDevicePlugin *plugin = (SonyCameraDevicePlugin *)self.plugin; + SonyCameraManager *manager = plugin.sonyCameraManager; + NSString *serviceId = [request serviceId]; + NSString *target = [DConnectMediaStreamRecordingProfile targetFromRequest:request]; + + // サービスIDのチェック + if (![manager isConnectedService:serviceId]) { + [response setErrorToIllegalDeviceStateWithMessage:@"Sony's camera is not ready."]; + return YES; + } + + // ターゲットチェック + if (target && ![target isEqualToString:SONY_TARGET_ID]) { + [response setErrorToInvalidRequestParameterWithMessage:@"target is invalid."]; + return YES; + } + + DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[self.plugin class]]; + DConnectEventError error = [mgr removeEventForRequest:request]; + if (error == DConnectEventErrorNone) { + [response setResult:DConnectMessageResultTypeOk]; + } else if (error == DConnectEventErrorInvalidParameter + || error == DConnectEventErrorNotFound) { + [response setErrorToInvalidRequestParameter]; + } else { + [response setErrorToUnknown]; + } + return YES; +} + +- (BOOL) didReceivePutPreviewRequest:(DConnectRequestMessage *)request response:(DConnectResponseMessage *)response +{ + SonyCameraDevicePlugin *plugin = (SonyCameraDevicePlugin *)self.plugin; + SonyCameraManager *manager = plugin.sonyCameraManager; + NSString *serviceId = [request serviceId]; + NSNumber *timeSlice = [request numberForKey:@"timeSlice"]; + NSString *target = [DConnectMediaStreamRecordingProfile targetFromRequest:request]; + + // サービスIDのチェック + if (![manager isConnectedService:serviceId]) { + [response setErrorToIllegalDeviceStateWithMessage:@"Sony's camera is not ready."]; + return YES; + } + + // ターゲットチェック + if (target && ![target isEqualToString:SONY_TARGET_ID]) { + [response setErrorToInvalidRequestParameterWithMessage:@"target is invalid."]; + return YES; + } + + [manager startPreviewWithTimeSlice:timeSlice block:^(NSString *uri) { + if (uri) { + [response setResult:DConnectMessageResultTypeOk]; + [response setString:uri forKey:@"uri"]; + } else { + [response setErrorToUnknown]; + } + [[DConnectManager sharedManager] sendResponse:response]; + }]; + + return NO; +} + +- (BOOL) didReceiveDeletePreviewRequest:(DConnectRequestMessage *)request response:(DConnectResponseMessage *)response +{ + SonyCameraDevicePlugin *plugin = (SonyCameraDevicePlugin *)self.plugin; + SonyCameraManager *manager = plugin.sonyCameraManager; + NSString *serviceId = [request serviceId]; + NSString *target = [DConnectMediaStreamRecordingProfile targetFromRequest:request]; + + // サービスIDのチェック + if (![manager isConnectedService:serviceId]) { + [response setErrorToIllegalDeviceStateWithMessage:@"Sony's camera is not ready."]; + return YES; + } + + // ターゲットチェック + if (target && ![target isEqualToString:SONY_TARGET_ID]) { + [response setErrorToInvalidRequestParameterWithMessage:@"target is invalid."]; + return YES; + } + + // プレビューチェック + if (![manager isPreview]) { + [response setErrorToIllegalDeviceStateWithMessage:@"Sony's camera is not running a preview."]; + return YES; + } + + [manager stopPreview]; + + [response setResult:DConnectMessageResultTypeOk]; + return YES; +} + + @end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraSystemProfile.m b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraSystemProfile.m index 52c42e7c..8a8b4efc 100644 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraSystemProfile.m +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/Classes/profile/SonyCameraSystemProfile.m @@ -14,9 +14,6 @@ #import "SonyCameraViewController.h" #import "SonyCameraManager.h" -#define DCBundle() \ -[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"DConnectSDK_resources" ofType:@"bundle"]] - /*! @brief バージョン。 */ @@ -39,6 +36,7 @@ - (instancetype)init if (self) { self.delegate = self; self.dataSource = self; + __weak SonyCameraSystemProfile *weakSelf = self; // イベントマネージャを取得 @@ -49,9 +47,7 @@ - (instancetype)init attributeName: DConnectSystemProfileAttrWakeUp]; [self addPutPath: putSettingPageForRequestApiPath api:^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - BOOL send = [weakSelf didReceivePutWakeupRequest:request response:response]; - return send; + return [weakSelf didReceivePutWakeupRequest:request response:response]; }]; // API登録(didReceiveDeleteEventsRequest相当) @@ -59,32 +55,30 @@ - (instancetype)init attributeName: DConnectSystemProfileAttrEvents]; [self addDeletePath: deleteEventsRequestApiPath api:^BOOL(DConnectRequestMessage *request, DConnectResponseMessage *response) { - - NSString *origin = [request origin]; - - if (origin == nil) { - [response setErrorToInvalidRequestParameterWithMessage:@"origin is nil"]; - } else { - DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[SonyCameraDevicePlugin class]]; - if ([mgr removeEventsForOrigin:origin]) { - [response setResult:DConnectMessageResultTypeOk]; - - // 削除した時にイベントが残っていなければ、プレビューを止める - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - if (![self hasDataAvaiableEvent] && [[manager remoteApi] isStartedLiveView]) { - [[manager remoteApi] actStopLiveView]; - } - } else { - [response setErrorToUnknownWithMessage:@"Cannot delete events."]; - } - } - return YES; + return [weakSelf didReceiveDeleteEventsRequest:request response:response]; }]; } return self; } +- (BOOL) didReceiveDeleteEventsRequest:(DConnectRequestMessage *)request response:(DConnectResponseMessage *)response +{ + NSString *origin = [request origin]; + + if (origin == nil) { + [response setErrorToInvalidRequestParameterWithMessage:@"origin is nil"]; + } else { + DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[SonyCameraDevicePlugin class]]; + if ([mgr removeEventsForOrigin:origin]) { + [response setResult:DConnectMessageResultTypeOk]; + } else { + [response setErrorToUnknownWithMessage:@"Cannot delete events."]; + } + } + return YES; +} + #pragma mark - DConnectSystemProfileDataSource - (NSString *) versionOfSystemProfile:(DConnectSystemProfile *)profile { @@ -101,35 +95,8 @@ - (UIViewController *) profile:(DConnectSystemProfile *)sender DConnectServiceListViewController *serviceListViewController = (DConnectServiceListViewController *) top.viewControllers[0]; serviceListViewController.delegate = self; return top; - -/* - NSString *bundlePath = [[NSBundle mainBundle] - pathForResource:@"dConnectDeviceSonyCamera_resources" - ofType:@"bundle"]; - NSBundle *bundle = [NSBundle bundleWithPath:bundlePath]; - - // iphoneとipadでストーリーボードを切り替える - UIStoryboard *storyBoard; - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { - storyBoard = [UIStoryboard storyboardWithName:@"SonyCameraDevicePlugin_iPhone" bundle:bundle]; - } else{ - storyBoard = [UIStoryboard storyboardWithName:@"SonyCameraDevicePlugin_iPad" bundle:bundle]; - } - UINavigationController *viewController = [storyBoard instantiateInitialViewController]; - SonyCameraManager *manager = [SonyCameraManager sharedManager]; - for (int i = 0; i < viewController.viewControllers.count; i++) { - UIViewController *ctl = viewController.viewControllers[i]; - NSString *className = NSStringFromClass([ctl class]); - if ([className isEqualToString:@"SonyCameraViewController"]) { - SonyCameraViewController *scvc = (SonyCameraViewController *) ctl; - scvc.deviceplugin = manager.plugin; - } - } - return viewController; -*/ } - #pragma mark - DConnectSystemProfileDelegate - (DConnectServiceProvider *)serviceProvider { @@ -137,10 +104,7 @@ - (DConnectServiceProvider *)serviceProvider { } - (UIViewController *)settingViewController { - NSString *bundlePath = [[NSBundle mainBundle] - pathForResource:@"dConnectDeviceSonyCamera_resources" - ofType:@"bundle"]; - NSBundle *bundle = [NSBundle bundleWithPath:bundlePath]; + NSBundle *bundle = DPSonyCameraBundle(); // iphoneとipadでストーリーボードを切り替える UIStoryboard *storyBoard; @@ -150,7 +114,9 @@ - (UIViewController *)settingViewController { storyBoard = [UIStoryboard storyboardWithName:@"SonyCameraDevicePlugin_iPad" bundle:bundle]; } UINavigationController *viewController = [storyBoard instantiateInitialViewController]; - SonyCameraManager *manager = [SonyCameraManager sharedManager]; + + SonyCameraDevicePlugin *plugin = (SonyCameraDevicePlugin *) self.plugin; + SonyCameraManager *manager = plugin.sonyCameraManager; for (int i = 0; i < viewController.viewControllers.count; i++) { UIViewController *ctl = viewController.viewControllers[i]; NSString *className = NSStringFromClass([ctl class]); @@ -162,15 +128,9 @@ - (UIViewController *)settingViewController { return viewController; } - -#pragma mark - Primate Methods. - -- (BOOL) hasDataAvaiableEvent { - DConnectEventManager *mgr = [DConnectEventManager sharedManagerForClass:[SonyCameraDevicePlugin class]]; - NSArray *evts = [mgr eventListForServiceId:SERVICE_ID - profile:DConnectMediaStreamRecordingProfileName - attribute:DConnectMediaStreamRecordingProfileAttrOnDataAvailable]; - return evts.count > 0; +- (void)didRemovedService:(DConnectService *)service +{ + [self.plugin removeSonyCamera:service]; } @end diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera-Prefix.pch b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera-Prefix.pch index 2adf058a..bfc26df6 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera-Prefix.pch +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera-Prefix.pch @@ -14,6 +14,29 @@ #import #endif -#ifndef DEBUG -#define NSLog(...) + +#ifdef DEBUG +#define DCLogInfo(fmt, ...) NSLog((@"%s:INFO: " fmt), class_getName([self class]), ##__VA_ARGS__) +#define DCLogInfo2(tag, fmt, ...) NSLog((@"%@:INFO: " fmt), (tag), ##__VA_ARGS__) +#else +#define DCLogInfo(...) +#define DCLogInfo2(...) +#endif + +#ifdef DEBUG +#define DCLogWarn(fmt, ...) NSLog((@"%s:WARN: " fmt), class_getName([self class]), ##__VA_ARGS__) +#define DCLogWarn2(tag, fmt, ...) NSLog((@"%@:WARN: " fmt), (tag), ##__VA_ARGS__) +#else +#define DCLogWarn(...) +#define DCLogWarn2(...) #endif + +#define DCLogError(fmt, ...) NSLog((@"%s:ERROR: " fmt), class_getName([self class]), ##__VA_ARGS__) +#define DCLogError2(tag, fmt, ...) NSLog((@"%@:ERROR: " fmt), (tag), ##__VA_ARGS__) + + +#define DCBundle() \ +[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"DConnectSDK_resources" ofType:@"bundle"]] + +#define DPSonyCameraBundle() \ +[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"dConnectDeviceSonyCamera_resources" ofType:@"bundle"]] diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera_resources/SonyCameraDevicePlugin_iPad.storyboard b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera_resources/SonyCameraDevicePlugin_iPad.storyboard index 2a3feb0e..405073c3 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera_resources/SonyCameraDevicePlugin_iPad.storyboard +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera_resources/SonyCameraDevicePlugin_iPad.storyboard @@ -1,7 +1,12 @@ - - + + + + + - + + + @@ -9,6 +14,7 @@ + @@ -30,7 +36,7 @@ - + @@ -61,10 +67,10 @@ - + - + @@ -99,13 +105,16 @@ + + - + + Sonyカメラ(*)とのWiFi接続を行います。画像はQX10のものです。 接続するSonyカメラのSSIDとパスワードを確認してください。 @@ -117,7 +126,8 @@ QXの場合は、バッテリーカバーの裏に書かれています。他の - + + Sonyカメラの電源ボタンを押します。 QX10ならばランプが緑に点灯し本体からレンズが身長します。 @@ -128,21 +138,22 @@ AS30は本体背部のRECボタンを押すことで電源がONになります - + + - + - + - + @@ -173,35 +184,38 @@ AS30は本体背部のRECボタンを押すことで電源がONになります - + + - + - - 下に表示されているカメラ検索ボタンを押下してください。 - + + - + - + - + @@ -258,12 +273,13 @@ AS30は本体背部のRECボタンを押すことで電源がONになります - + - + + iOSの設定画面からWiFiを有効にします。 ネットワークを選択からカメラのSSIDを選択します。 @@ -274,25 +290,27 @@ AS30は本体背部のRECボタンを押すことで電源がONになります + - - + + + - + - + - + diff --git a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera_resources/SonyCameraDevicePlugin_iPhone.storyboard b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera_resources/SonyCameraDevicePlugin_iPhone.storyboard index 711c8c63..c2bc2553 100755 --- a/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera_resources/SonyCameraDevicePlugin_iPhone.storyboard +++ b/dConnectDevicePlugin/dConnectDeviceSonyCamera/dConnectDeviceSonyCamera_resources/SonyCameraDevicePlugin_iPhone.storyboard @@ -1,8 +1,12 @@ - - + + + + + - + + @@ -14,49 +18,89 @@ - + - - + + - - - - Sonyカメラ(*)とのWiFi接続を行います。画像はQX10のものです。 + + + + + + + + + + + + + + + + + + ※対応機種一覧:HDR-AS15, HDR-AS30, HDR-AS100,HDR-AS20,HDR-MV1, A7, A7R, A7S, NEX-6, NEX-5R, NEX-5T, A5000, A6000, DSC-HX60, DSC-HX400, DSC-RX100M3 + + + + + + + + + + + Sonyカメラ(*)とのWiFi接続を行います。画像はQX10のものです。 接続するSonyカメラのSSIDとパスワードを確認してください。 QXの場合は、バッテリーカバーの裏に書かれています。他のカメラは、取扱説明書などで確認してください。 - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + - - - + @@ -67,50 +111,89 @@ QXの場合は、バッテリーカバーの裏に書かれています。他の - + - - + + - - - - - - - iOSの設定画面からWiFiを有効にします。 + + + + + + + + + + + + + + + + + + iOSの設定画面からWiFiを有効にします。 ネットワークを選択からカメラのSSIDを選択します。 ネットワークに接続するときにパスワードを入力してください。 - - - - - - - 注意) モバイルデータ通信をオフに + + + + + + + + + + + 注意) モバイルデータ通信をオフに してください。 - - - - + + + + + + + + + + + + + + + + - - + + + + + + + + - + + + + + + + - + - + @@ -121,57 +204,109 @@ QXの場合は、バッテリーカバーの裏に書かれています。他の - + - - + + - - - - - - - - - - - - - - + + + + + + + + - + + + + + + + - + @@ -179,7 +314,7 @@ QXの場合は、バッテリーカバーの裏に書かれています。他の - + @@ -190,47 +325,81 @@ QXの場合は、バッテリーカバーの裏に書かれています。他の - + - - + + - - - - - - - Sonyカメラの電源ボタンを押します。 + + + + + + + + + + + Sonyカメラの電源ボタンを押します。 QX10ならばランプが緑に点灯し本体からレンズが身長します。 AS30は本体背部のRECボタンを押すことで電源がONになります。他の対応機種については取扱説明書を参照してください。 - - - + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + - + + + + + + + - + - + + @@ -250,13 +419,13 @@ AS30は本体背部のRECボタンを押すことで電源がONになります - + - + - + @@ -277,4 +446,9 @@ AS30は本体背部のRECボタンを押すことで電源がONになります + + + + + diff --git a/dConnectSDK/dConnectSDKForIOS/DConnectSDK/Classes/profile/DConnectMediaStreamRecordingProfile.m b/dConnectSDK/dConnectSDKForIOS/DConnectSDK/Classes/profile/DConnectMediaStreamRecordingProfile.m index 49343f8c..367a3725 100755 --- a/dConnectSDK/dConnectSDKForIOS/DConnectSDK/Classes/profile/DConnectMediaStreamRecordingProfile.m +++ b/dConnectSDK/dConnectSDKForIOS/DConnectSDK/Classes/profile/DConnectMediaStreamRecordingProfile.m @@ -10,7 +10,7 @@ #import "DConnectMediaStreamRecordingProfile.h" NSString *const DConnectMediaStreamRecordingProfileName = @"mediastreamRecording"; -NSString *const DConnectMediaStreamRecordingProfileAttrMediaRecorder = @"mediarecorder"; +NSString *const DConnectMediaStreamRecordingProfileAttrMediaRecorder = @"recorder"; NSString *const DConnectMediaStreamRecordingProfileAttrTakePhoto = @"takephoto"; NSString *const DConnectMediaStreamRecordingProfileAttrRecord = @"record"; NSString *const DConnectMediaStreamRecordingProfileAttrPause = @"pause"; diff --git a/dConnectSDK/dConnectSDKForIOS/DConnectSDK/Classes/viewcontroller/DConnectServiceListViewController.m b/dConnectSDK/dConnectSDKForIOS/DConnectSDK/Classes/viewcontroller/DConnectServiceListViewController.m index e36942fe..dddad6e4 100644 --- a/dConnectSDK/dConnectSDKForIOS/DConnectSDK/Classes/viewcontroller/DConnectServiceListViewController.m +++ b/dConnectSDK/dConnectSDKForIOS/DConnectSDK/Classes/viewcontroller/DConnectServiceListViewController.m @@ -171,9 +171,6 @@ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEd [tableView beginUpdates]; [self.delegate.serviceProvider removeService: service]; [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; - if ([self.delegate respondsToSelector:@selector(didRemoveService:)]) { - [self.delegate didRemoveService: service]; - } [tableView endUpdates]; // 削除後にオフラインのサービスが1件以上あればRemoveボタンを有効にする @@ -286,6 +283,10 @@ - (void)didServiceRemoved:(DConnectService *)service { [self setEditing:NO animated:YES]; } + if ([self.delegate respondsToSelector:@selector(didRemovedService:)]) { + [self.delegate didRemovedService:service]; + } + // サービスが追加されたらtableViewを更新する [self.tableView reloadData]; diff --git a/dConnectSDK/dConnectSDKForIOS/DConnectSDK/DConnectSDK/DConnectSystemProfile.h b/dConnectSDK/dConnectSDKForIOS/DConnectSDK/DConnectSDK/DConnectSystemProfile.h index 8fc2e287..d18c8f73 100755 --- a/dConnectSDK/dConnectSDKForIOS/DConnectSDK/DConnectSDK/DConnectSystemProfile.h +++ b/dConnectSDK/dConnectSDKForIOS/DConnectSDK/DConnectSDK/DConnectSystemProfile.h @@ -88,10 +88,20 @@ extern NSString *const DConnectSystemProfileParamVersion; @optional -- (void) didRemoveService: (DConnectService *) service; - +/*! + @brief サービスが選択された時に呼び出します. + + @param[in] service 選択されたサービス + */ - (void) didSelectService: (DConnectService *) service; +/*! + @brief サービスが削除された時に呼び出します. + + @param[in] service 削除されたサービス + */ +- (void) didRemovedService:(DConnectService *) service; + - (void) serviceListViewControllerDidWillAppear; - (NSArray *) displayServiceFilter: (NSArray *) services;