blob: f6f5f54e151c99e8462db51d6675682eb467e5ba [file] [log] [blame]
atraczyke9919eb2016-09-15 15:58:18 -04001/**************************************************************************
2* Copyright (C) 2016 by Savoir-faire Linux *
3* Author: Jäger Nicolas <nicolas.jager@savoirfairelinux.com> *
4* Author: Traczyk Andreas <andreas.traczyk@savoirfairelinux.com> *
5* *
6* This program is free software; you can redistribute it and/or modify *
7* it under the terms of the GNU General Public License as published by *
8* the Free Software Foundation; either version 3 of the License, or *
9* (at your option) any later version. *
10* *
11* This program is distributed in the hope that it will be useful, *
12* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14* GNU General Public License for more details. *
15* *
16* You should have received a copy of the GNU General Public License *
17* along with this program. If not, see <http://www.gnu.org/licenses/>. *
18**************************************************************************/
Nicolas Jagere069c412016-08-15 15:00:17 -040019#include "pch.h"
20
21#include "VideoPage.xaml.h"
22
atraczyk14ba30c2016-09-22 18:31:59 -040023#include <MemoryBuffer.h> // IMemoryBufferByteAccess
24
Nicolas Jagere069c412016-08-15 15:00:17 -040025using namespace RingClientUWP::Views;
Nicolas Jagerc551c362016-10-01 19:24:50 -040026using namespace ViewModel;
atraczyk14ba30c2016-09-22 18:31:59 -040027using namespace Video;
Nicolas Jagere069c412016-08-15 15:00:17 -040028
29using namespace Concurrency;
30using namespace Platform;
31using namespace Windows::Devices::Enumeration;
32using namespace Windows::Foundation;
33using namespace Windows::Foundation::Collections;
34using namespace Windows::UI::Xaml;
35using namespace Windows::UI::Xaml::Controls;
36using namespace Windows::UI::Xaml::Controls::Primitives;
37using namespace Windows::UI::Xaml::Data;
38using namespace Windows::UI::Xaml::Input;
39using namespace Windows::UI::Xaml::Media;
40using namespace Windows::UI::Xaml::Navigation;
41using namespace Windows::Media::Capture;
atraczyke9919eb2016-09-15 15:58:18 -040042using namespace Windows::ApplicationModel::Core;
43using namespace Windows::UI::Core;
Nicolas Jagere069c412016-08-15 15:00:17 -040044
atraczyk14ba30c2016-09-22 18:31:59 -040045using namespace Windows::Graphics::Display;
46using namespace Windows::Graphics::Imaging;
47using namespace Windows::Media;
48using namespace Windows::UI::Xaml::Media::Imaging;
49using namespace Windows::Media::Capture;
50using namespace Windows::Devices::Sensors;
51
Nicolas Jagere069c412016-08-15 15:00:17 -040052VideoPage::VideoPage()
53{
54 InitializeComponent();
atraczyk14ba30c2016-09-22 18:31:59 -040055
56 VideoManager::instance->captureManager()->displayInformation = DisplayInformation::GetForCurrentView();
57 VideoManager::instance->captureManager()->EnumerateWebcamsAsync();
58
59 Page::NavigationCacheMode = Navigation::NavigationCacheMode::Required;
60
61 VideoManager::instance->rendererManager()->writeVideoFrame +=
62 ref new WriteVideoFrame([this](String^ id, uint8_t* buf, int width, int height)
63 {
Nicolas Jager9edbea32016-10-03 09:13:53 -040064 CoreApplication::MainView->CoreWindow->Dispatcher->RunAsync(CoreDispatcherPriority::High,
atraczyk14ba30c2016-09-22 18:31:59 -040065 ref new DispatchedHandler([=]() {
66 try {
67 if (!VideoManager::instance->rendererManager()->renderers->Size)
68 return;
69 VideoManager::instance->rendererManager()->renderer(id)->isRendering = true;
70 create_task(WriteFrameAsSoftwareBitmapAsync(id, buf, width, height))
Nicolas Jager9edbea32016-10-03 09:13:53 -040071 .then([=](task<void> previousTask) {
atraczyk14ba30c2016-09-22 18:31:59 -040072 try {
73 previousTask.get();
74 }
75 catch (Platform::Exception^ e) {
76 WriteLine( "Caught exception from previous task.\n" );
77 }
78 });
79 }
80 catch(Platform::COMException^ e) {
81 WriteLine(e->ToString());
82 }
83 }));
84 });
85
86 VideoManager::instance->captureManager()->startPreviewing +=
87 ref new StartPreviewing([this]()
88 {
89 PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Visible;
90 PreviewImage->FlowDirection = VideoManager::instance->captureManager()->mirroringPreview ?
Nicolas Jager9edbea32016-10-03 09:13:53 -040091 Windows::UI::Xaml::FlowDirection::RightToLeft :
92 Windows::UI::Xaml::FlowDirection::LeftToRight;
atraczyk14ba30c2016-09-22 18:31:59 -040093 });
94
95 VideoManager::instance->captureManager()->stopPreviewing +=
96 ref new StopPreviewing([this]()
97 {
98 PreviewImage->Source = nullptr;
99 PreviewImage->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
100 });
101
102 VideoManager::instance->captureManager()->getSink +=
103 ref new GetSink([this]()
104 {
105 return PreviewImage;
106 });
107
108 VideoManager::instance->rendererManager()->clearRenderTarget +=
109 ref new ClearRenderTarget([this]()
110 {
111 IncomingVideoImage->Source = nullptr;
112 });
113
114 RingD::instance->incomingAccountMessage +=
115 ref new IncomingAccountMessage([&](String^ accountId, String^ from, String^ payload)
116 {
117 scrollDown();
118 });
119
120 RingD::instance->stateChange +=
121 ref new StateChange([&](String^ callId, CallStatus state, int code)
122 {
123 if (state == CallStatus::ENDED) {
124 Video::VideoManager::instance->rendererManager()->raiseClearRenderTarget();
125 }
126 });
127
128 RingD::instance->incomingAccountMessage += ref new IncomingAccountMessage([&](String^ accountId,
129 String^ from, String^ payload) {
130 scrollDown();
131 });
Nicolas Jagere069c412016-08-15 15:00:17 -0400132}
133
atraczyke9919eb2016-09-15 15:58:18 -0400134void
135RingClientUWP::Views::VideoPage::OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e)
136{
137 updatePageContent();
138}
Nicolas Jagere069c412016-08-15 15:00:17 -0400139
atraczyke9919eb2016-09-15 15:58:18 -0400140void RingClientUWP::Views::VideoPage::updatePageContent()
141{
Nicolas Jagerc551c362016-10-01 19:24:50 -0400142 auto item = SmartPanelItemsViewModel::instance->_selectedItem;
143 auto contact = (item) ? item->_contact : nullptr;
144
atraczyke9919eb2016-09-15 15:58:18 -0400145 if (!contact)
146 return;
147
148 _callee_->Text = contact->name_;
atraczyk5c395ea2016-09-20 17:28:09 -0400149
150 _messagesList_->ItemsSource = contact->_conversation->_messages;
151
152 scrollDown();
153}
154
155void RingClientUWP::Views::VideoPage::scrollDown()
156{
157 _scrollView_->UpdateLayout();
158 _scrollView_->ScrollToVerticalOffset(_scrollView_->ScrollableHeight);
159}
160
161void
162RingClientUWP::Views::VideoPage::_sendBtn__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
163{
164 sendMessage();
165}
166
167void
168RingClientUWP::Views::VideoPage::_messageTextBox__KeyDown(Platform::Object^ sender, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e)
169{
170 if (e->Key == Windows::System::VirtualKey::Enter) {
171 sendMessage();
172 }
173}
174
175void
176RingClientUWP::Views::VideoPage::sendMessage()
177{
Nicolas Jagerc551c362016-10-01 19:24:50 -0400178 auto item = SmartPanelItemsViewModel::instance->_selectedItem;
179 auto contact = item->_contact;
180
atraczyk5c395ea2016-09-20 17:28:09 -0400181 auto txt = _messageTextBox_->Text;
182
183 /* empty the textbox */
184 _messageTextBox_->Text = "";
185
186 if (!contact || txt->IsEmpty())
187 return;
188
atraczyk11e7baf2016-10-05 13:08:08 -0400189 RingD::instance->sendSIPTextMessage(txt);
atraczyk5c395ea2016-09-20 17:28:09 -0400190 scrollDown();
atraczyke9919eb2016-09-15 15:58:18 -0400191}
Nicolas Jagere069c412016-08-15 15:00:17 -0400192
193void RingClientUWP::Views::VideoPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
194{
195}
196
197
198void RingClientUWP::Views::VideoPage::_btnCancel__Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
199{
200
201}
202
203void RingClientUWP::Views::VideoPage::_btnHangUp__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e)
204{
Nicolas Jagerc551c362016-10-01 19:24:50 -0400205 auto item = SmartPanelItemsViewModel::instance->_selectedItem;
Nicolas Jager083b3ae2016-10-04 08:46:19 -0400206 RingD::instance->hangUpCall2(item->_callId);
Nicolas Jager9edbea32016-10-03 09:13:53 -0400207
Nicolas Jagere069c412016-08-15 15:00:17 -0400208 pressHangUpCall();
209}
210
211
212void RingClientUWP::Views::VideoPage::_btnPause__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e)
213{
214 pauseCall();
215}
216
217
218void RingClientUWP::Views::VideoPage::_btnChat__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e)
219{
atraczyk5c395ea2016-09-20 17:28:09 -0400220 chatOpen = !chatOpen;
221 if (chatOpen) {
222 _rowChatBx_->Height = 200;
223 chatPanelCall();
224 }
225 else {
226 _rowChatBx_->Height = 0;
227 }
Nicolas Jagere069c412016-08-15 15:00:17 -0400228}
229
230
231void RingClientUWP::Views::VideoPage::_btnAddFriend__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e)
232{
233 addContactCall();
234}
235
236
237void RingClientUWP::Views::VideoPage::_btnSwitch__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e)
238{
239 transferCall();
240}
241
242
243void RingClientUWP::Views::VideoPage::_btnMicrophone__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e)
244{
245 switchMicrophoneStateCall();
246}
247
248
249void RingClientUWP::Views::VideoPage::_btnMemo__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e)
250{
251 reccordVideoCall();
252}
253
254
255void RingClientUWP::Views::VideoPage::_btnHQ__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e)
256{
257 qualityVideoLevelCall();
258}
259
260
261void RingClientUWP::Views::VideoPage::_btnVideo__Tapped(Platform::Object^ sender, Windows::UI::Xaml::Input::TappedRoutedEventArgs^ e)
262{
263 switchVideoStateCall();
264}
265
266
267void RingClientUWP::Views::VideoPage::_videoControl__PointerMoved(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e)
268{
269 if (barFading)
270 myStoryboard->Begin();
271 barFading_ = true;
272}
273
274
275void RingClientUWP::Views::VideoPage::btnAny_entered(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e)
276{
277 barFading_ = false;
278 myStoryboard->Stop();
279}
280
281
282void RingClientUWP::Views::VideoPage::btnAny_exited(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e)
283{
284 barFading_ = true;
atraczyk14ba30c2016-09-22 18:31:59 -0400285}
286
287task<void>
288VideoPage::WriteFrameAsSoftwareBitmapAsync(String^ id, uint8_t* buf, int width, int height)
289{
290 auto vframe = ref new VideoFrame(BitmapPixelFormat::Bgra8, width, height);
291 auto frame = vframe->SoftwareBitmap;
292
293 const int BYTES_PER_PIXEL = 4;
294
295 BitmapBuffer^ buffer = frame->LockBuffer(BitmapBufferAccessMode::ReadWrite);
296 IMemoryBufferReference^ reference = buffer->CreateReference();
297
298 Microsoft::WRL::ComPtr<IMemoryBufferByteAccess> byteAccess;
299 if (SUCCEEDED(reinterpret_cast<IUnknown*>(reference)->QueryInterface(IID_PPV_ARGS(&byteAccess))))
300 {
301 byte* data;
302 unsigned capacity;
303 byteAccess->GetBuffer(&data, &capacity);
304
305 auto desc = buffer->GetPlaneDescription(0);
306
307 for (int row = 0; row < desc.Height; row++)
308 {
309 for (int col = 0; col < desc.Width; col++)
310 {
311 auto currPixel = desc.StartIndex + desc.Stride * row + BYTES_PER_PIXEL * col;
312
313 data[currPixel + 0] = buf[currPixel + 0];
314 data[currPixel + 1] = buf[currPixel + 1];
315 data[currPixel + 2] = buf[currPixel + 2];
316 }
317 }
318 }
319 delete reference;
320 delete buffer;
321
322 VideoManager::instance->rendererManager()->renderer(id)->isRendering = false;
323
324 auto sbSource = ref new Media::Imaging::SoftwareBitmapSource();
325 return create_task(sbSource->SetBitmapAsync(frame))
Nicolas Jager9edbea32016-10-03 09:13:53 -0400326 .then([this, sbSource]()
atraczyk14ba30c2016-09-22 18:31:59 -0400327 {
328 try {
329 IncomingVideoImage->Source = sbSource;
330 }
331 catch (Exception^ e) {
332 WriteException(e);
333 }
334 });
335}