private void RecordVideo(ApiRequest request) { _recordVideoWindow = RecordVideoWindow.Create(_webSocketServer); _recordVideoWindow.SetFormat(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.Format, ShouldRecordAsLandscape(request.CurrentBook), request.CurrentBook.GetLayout()); _recordVideoWindow.SetPageReadTime(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.PageTurnDelayDouble.ToString()); _recordVideoWindow.SetVideoSettingsFromPreview(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.PlayerSettings); _recordVideoWindow.SetPageRange(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.PageRange); _recordVideoWindow.FinishedProcessingRecording += (sender, args) => { if (!_recordVideoWindow.GotFullRecording) { _recordVideoWindow.Cleanup(); _recordVideoWindow = null; } }; _recordVideoWindow.Show(PublishToAndroidApi.PreviewUrl, request.CurrentBook.FolderPath); }
public void RegisterWithApiHandler(BloomApiHandler apiHandler) { apiHandler.RegisterEndpointHandler(kApiUrlPart + "recordVideo", request => { RecordVideo(request); request.PostSucceeded(); }, true, false); // This is sent directly from BloomPlayer when it gets to the end of making the recording. // The player gives Bloom a list of all the sounds it played and their timings so we can // merge them into the captured video. apiHandler.RegisterEndpointHandler(kApiUrlPart + "soundLog", request => { var soundLog = request.RequiredPostJson(); _recordVideoWindow.StopRecording(soundLog); request.PostSucceeded(); }, true, false); apiHandler.RegisterEndpointHandler(kApiUrlPart + "playVideo", request => { _recordVideoWindow.PlayVideo(); request.PostSucceeded(); }, true, false); apiHandler.RegisterEndpointHandler(kApiUrlPart + "settings", request => { if (request.HttpMethod == HttpMethods.Get) { var settings = request.CurrentBook.BookInfo.PublishSettings.AudioVideo; var lastPageIndex = request.CurrentBook.GetPages().Count() - 1; // this default might be too high but I don't think it will ever be too low. // The HTML side will handle it being too high. var pageRange = new[] { 0, lastPageIndex }; if (settings.PageRange != null && settings.PageRange.Length == 2) { // I wanted to do something like this as validation, in case the book changed // since we saved. But we don't have an accurate page count of the modified version // of the book that the range applies to yet. (e.g., switch to device xmatter, strip // activities,... //pageRange[1] = Math.Min(settings.PageRange[1], lastPageIndex); // not more than the pages we have //pageRange[0] = Math.Min(settings.PageRange[0], pageRange[1] - 1); // at least one less than lim //if (pageRange[0] < 0) // pageRange[0] = 0; //if (pageRange[1] < pageRange[0] + 1) // pageRange[1] = Math.Min(pageRange[0] + 1, lastPageIndex); pageRange = settings.PageRange; } request.ReplyWithJson(new { format = settings.Format, pageTurnDelay = settings.PageTurnDelayDouble, motion = settings.Motion, pageRange }); } else { var data = DynamicJson.Parse(request.RequiredPostJson()); var settings = request.CurrentBook.BookInfo.PublishSettings.AudioVideo; var oldMotion = settings.Motion; settings.Format = data.format; settings.PageTurnDelayDouble = data.pageTurnDelay; settings.Motion = data.motion; // pageRange also comes in as doubles. "as double[]" does not work, so have to do them individually. settings.PageRange = new int[0]; // Typescript passes an empty array if all pages are selected. // This allows us naturally to keep everything selected until the user explicitly changes something. if (data.pageRange.IsArray && data.pageRange.Count == 2) { var start = (int)data.pageRange[0]; var end = (int)data.pageRange[1]; settings.PageRange = new[] { start, end }; } request.CurrentBook.BookInfo.SavePublishSettings(); _recordVideoWindow?.SetPageReadTime(settings.PageTurnDelayDouble.ToString()); _recordVideoWindow?.SetFormat(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.Format, ShouldRecordAsLandscape(request.CurrentBook), request.CurrentBook.GetLayout()); if (settings.Motion != oldMotion) { UpdatePreview(request); // does its own success/fail } else { request.PostSucceeded(); } } }, true, false); apiHandler.RegisterEndpointHandler(kApiUrlPart + "videoSettings", request => { if (request.HttpMethod == HttpMethods.Get) { request.ReplyWithText(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.PlayerSettings ?? ""); } else { request.CurrentBook.BookInfo.PublishSettings.AudioVideo.PlayerSettings = request.RequiredPostString(); request.CurrentBook.BookInfo.SavePublishSettings(); request.PostSucceeded(); } }, true, false); apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "hasActivities", request => { return(request.CurrentBook.HasActivities); }, null, // no write action false, true); // we don't really know, just safe default // Returns true if publish to MP3 is supported for this book, false otherwise. // To be eligible to publish to MP3, the book must contain narration audio. // (There's not any point to an MP3 if the book has absolutely no audio... // Even a book with background music but no narration, there's not too much point to an MP3 either) apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "isMP3FormatSupported", request => { // ENHANCE: If desired, you can make it only consider languages in the book that are currently relevant, // instead of any language in the book. var narrationAudioLangs = request.CurrentBook.GetLanguagesWithAudio(); return(narrationAudioLangs.Any()); }, null, false, false); apiHandler.RegisterEndpointHandler(kApiUrlPart + "startRecording", request => { var videoList = request.GetPostStringOrNull(); var anyVideoHasAudio = _recordVideoWindow?.AnyVideoHasAudio(videoList, request.CurrentBook.FolderPath) ?? false; if (anyVideoHasAudio) { var messageBoxButtons = new[] { new MessageBoxButton() { Text = LocalizationManager.GetString("Common.Continue", "Continue"), Id = "continue" }, new MessageBoxButton() { Text = LocalizationManager.GetString("Common.Cancel", "Cancel"), Id = "cancel", Default = true } }; if (BloomMessageBox.Show(null, LocalizationManager.GetString("PublishTab.RecordVideo.NoAudioInVideo", "Currently, Bloom does not support including audio from Sign Language videos in video output."), messageBoxButtons) == "cancel") { request.Failed("canceled"); _recordVideoWindow.Close(); return; } } _recordVideoWindow?.StartFfmpegForVideoCapture(); request.PostSucceeded(); }, true, false); apiHandler.RegisterEndpointHandler(kApiUrlPart + "shouldUseOriginalPageSize", request => { RecordVideoWindow.GetDataForFormat(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.Format, ShouldRecordAsLandscape(request.CurrentBook), request.CurrentBook.GetLayout(), out _, out _, out _, out bool useOriginalPageSize); request.ReplyWithBoolean(useOriginalPageSize); }, true, // has to be on UI thread because it uses Bloom's main window to find the right screen false); apiHandler.RegisterEndpointHandler(kApiUrlPart + "tooBigForScreenMsg", request => { request.ReplyWithText(RecordVideoWindow.GetDataForFormat(request.CurrentBook.BookInfo.PublishSettings.AudioVideo.Format, ShouldRecordAsLandscape(request.CurrentBook), request.CurrentBook.GetLayout(), out _, out _, out _, out _)); }, true, // has to be on UI thread because it uses Bloom's main window to find the right screen false); apiHandler.RegisterEndpointHandler(kApiUrlPart + "saveVideo", request => { if (_recordVideoWindow == null) { // This shouldn't be possible, but just in case, we'll kick off the recording now. RecordVideo(request); } _recordVideoWindow?.SetBook(request.CurrentBook); // If we bring up the dialog inside this API call, it may time out. Application.Idle += SaveVideoOnIdle; request.PostSucceeded(); }, true, false); apiHandler.RegisterEndpointHandler(kApiUrlPart + "updatePreview", request => { UpdatePreview(request); }, false); apiHandler.RegisterEndpointHandler(kApiUrlPart + "displaySettings", request => { Process.Start("desk.cpl"); request.PostSucceeded(); }, false); apiHandler.RegisterBooleanEndpointHandler(kApiUrlPart + "isScalingActive", request => IsScalingActive(), null, true); }