#include "pch.h" #include "ReactCameraConstants.h" #include "ReactCameraViewManager.h" #include namespace winrt { using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Controls; using namespace Windows::Devices::Enumeration; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; using namespace Windows::Media::MediaProperties; using namespace Windows::Storage; using namespace Windows::Storage::Streams; using namespace Microsoft::ReactNative; } // namespace winrt namespace winrt::ReactNativeCameraCPP::implementation { // static vector to contain all currently active camera view instances // This is a temporary workaround to map the view tag to view instance, since // Method call from ReactCameraModule constains view tag as parameter and we need // to forward the call to CameraView instance. std::vector> ReactCameraViewManager::m_cameraViewInstances; ReactCameraViewManager::ReactCameraViewManager() {} // IViewManager hstring ReactCameraViewManager::Name() noexcept { return L"RNCamera"; } FrameworkElement ReactCameraViewManager::CreateView() noexcept { auto const &view = ReactNativeCameraCPP::ReactCameraView::Create(); view->SetContext(m_reactContext); m_cameraViewInstances.emplace_back(view); return view.as(); } // IViewManagerWithReactContext IReactContext ReactCameraViewManager::ReactContext() noexcept { return m_reactContext; } void ReactCameraViewManager::ReactContext(IReactContext reactContext) noexcept { m_reactContext = reactContext; } // IViewManagerWithNativeProperties IMapView ReactCameraViewManager::NativeProps() noexcept { auto nativeProps = winrt::single_threaded_map(); nativeProps.Insert(L"aspect", ViewManagerPropertyType::Number); nativeProps.Insert(L"type", ViewManagerPropertyType::Number); nativeProps.Insert(L"cameraId", ViewManagerPropertyType::String); nativeProps.Insert(L"autoFocus", ViewManagerPropertyType::Boolean); nativeProps.Insert(L"whiteBalance", ViewManagerPropertyType::Number); nativeProps.Insert(L"torchMode", ViewManagerPropertyType::Number); nativeProps.Insert(L"flashMode", ViewManagerPropertyType::Number); nativeProps.Insert(L"barCodeScannerEnabled", ViewManagerPropertyType::Boolean); nativeProps.Insert(L"barCodeTypes", ViewManagerPropertyType::Array); nativeProps.Insert(L"barCodeReadIntervalMS", ViewManagerPropertyType::Number); nativeProps.Insert(L"keepAwake", ViewManagerPropertyType::Boolean); nativeProps.Insert(L"mirrorVideo", ViewManagerPropertyType::Boolean); nativeProps.Insert(L"defaultVideoQuality", ViewManagerPropertyType::Number); return nativeProps.GetView(); } void ReactCameraViewManager::UpdateProperties( FrameworkElement const &view, IJSValueReader const &propertyMapReader) noexcept { if (auto reactCameraView = view.try_as()) { reactCameraView->UpdateProperties(propertyMapReader); } } // IViewManagerWithExportedEventTypeConstants ConstantProviderDelegate ReactCameraViewManager::ExportedCustomBubblingEventTypeConstants() noexcept { return nullptr; } ConstantProviderDelegate ReactCameraViewManager::ExportedCustomDirectEventTypeConstants() noexcept { return [](winrt::Microsoft::ReactNative::IJSValueWriter const &constantWriter) { constantWriter.WritePropertyName(BarcodeReadEvent); constantWriter.WriteObjectBegin(); WriteProperty(constantWriter, L"registrationName", BarcodeReadEvent); constantWriter.WriteObjectEnd(); }; } void ReactCameraViewManager::RemoveViewFromList(winrt::com_ptr view) { auto it = std::find(m_cameraViewInstances.begin(), m_cameraViewInstances.end(), view); if (it != m_cameraViewInstances.end()) m_cameraViewInstances.erase(it); } IAsyncAction ReactCameraViewManager::TakePictureAsync( JSValueObject const &options, int viewTag, ReactPromise const &result) noexcept { auto capturedPromise = result; auto capturedOptions = options.Copy(); auto index = co_await FindCamera(viewTag); if (index != -1) { auto cameraView = m_cameraViewInstances.at(index); co_await cameraView->TakePictureAsync(capturedOptions, capturedPromise); } else { capturedPromise.Reject("No camera instance found."); } } IAsyncAction ReactCameraViewManager::RecordAsync( JSValueObject const &options, int viewTag, ReactPromise const &result) noexcept { auto capturedPromise = result; auto capturedOptions = options.Copy(); auto index = co_await FindCamera(viewTag); if (index != -1) { auto cameraView = m_cameraViewInstances.at(index); co_await cameraView->RecordAsync(capturedOptions, capturedPromise); } else { capturedPromise.Reject("No camera instance found."); } } IAsyncAction ReactCameraViewManager::StopRecordAsync(int viewTag) noexcept { auto index = co_await FindCamera(viewTag); if (index != -1) { auto cameraView = m_cameraViewInstances.at(index); co_await cameraView->StopRecordAsync(); } } IAsyncAction ReactCameraViewManager::IsRecordingAsync( int viewTag, winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept { auto capturedPromise = result; auto index = co_await FindCamera(viewTag); if (index != -1) { auto cameraView = m_cameraViewInstances.at(index); co_await cameraView->IsRecordingAsync(capturedPromise); } else { capturedPromise.Reject("No camera instance found."); } } IAsyncAction ReactCameraViewManager::PausePreviewAsync(int viewTag) noexcept { auto index = co_await FindCamera(viewTag); if (index != -1) { auto cameraView = m_cameraViewInstances.at(index); co_await cameraView->PausePreviewAsync(); } } IAsyncAction ReactCameraViewManager::ResumePreviewAsync(int viewTag) noexcept { auto index = co_await FindCamera(viewTag); if (index != -1) { auto cameraView = m_cameraViewInstances.at(index); co_await cameraView->ResumePreviewAsync(); } } // Intialize MediaCapture and will bring up the constent dialog if this // is the first time. RNC will display a progress indicator while waiting // for user click. This method will resolve as no permission if user does // not grant the permission or App does not have the appx capabilities for // Microphone and WebCam specified in its Package.Appxmanifest. IAsyncAction ReactCameraViewManager::CheckMediaCapturePermissionAsync( winrt::Microsoft::ReactNative::ReactPromise const &result) noexcept { auto capturedPromise = result; auto mediaCapture = winrt::Windows::Media::Capture::MediaCapture(); bool hasPermission = true; try { co_await mediaCapture.InitializeAsync(); } catch (winrt::hresult_error const &) { hasPermission = false; } capturedPromise.Resolve(hasPermission); } winrt::IAsyncAction ReactCameraViewManager::GetCameraIdsAsync( winrt::ReactPromise const &result) noexcept { auto capturedPromise = result; auto allVideoDevices = co_await winrt::DeviceInformation::FindAllAsync(winrt::DeviceClass::VideoCapture); winrt::JSValueArray resultArray; for (auto cameraDeviceInfo : allVideoDevices) { if (cameraDeviceInfo.IsEnabled()) { resultArray.push_back(winrt::JSValueObject{ {"id", winrt::to_string(cameraDeviceInfo.Id())}, {"name", winrt::to_string(cameraDeviceInfo.Name())}, {"type", cameraDeviceInfo.EnclosureLocation() ? static_cast(cameraDeviceInfo.EnclosureLocation().Panel()) : ReactCameraConstants::CameraTypeUnknown}, }); } } capturedPromise.Resolve(resultArray); co_return; } IAsyncOperation ReactCameraViewManager::FindCamera(int viewTag) noexcept { int index = 0; for (const auto &cameraView : m_cameraViewInstances) { auto element = cameraView.as(); auto dispatcher = element.Dispatcher(); co_await resume_foreground(dispatcher); int currentTag = static_cast( element.GetValue(winrt::FrameworkElement::TagProperty()).as().GetInt64()); if (currentTag == viewTag) { co_return index; } co_await resume_background(); index++; } co_return -1; } } // namespace winrt::ReactNativeCameraCPP::implementation