InCall.xaml.cs 13.4 KB
Newer Older
1 2
using Linphone.Core;
using Linphone.Model;
3
using Linphone.Resources;
4
using System;
5
using System.ComponentModel;
6
using System.Diagnostics;
7
using System.Threading;
8
using System.Windows;
9
using System.Windows.Controls;
10
using System.Windows.Media.Imaging;
11
using System.Windows.Navigation;
12 13 14

namespace Linphone.Views
{
15 16 17
    /// <summary>
    /// InCall page, displayed for both incoming and outgoing calls.
    /// </summary>
18
    public partial class InCall : BasePage, MuteChangedListener, PauseChangedListener
19 20 21 22 23 24 25
    {
        private const string speakerOn = "/Assets/AppBar/speaker.png";
        private const string speakerOff = "/Assets/AppBar/speaker.png";
        private const string micOn = "/Assets/AppBar/mic.png";
        private const string micOff = "/Assets/AppBar/mic.png";
        private const string pauseOn = "/Assets/AppBar/play.png";
        private const string pauseOff = "/Assets/AppBar/pause.png";
Ghislain MARY's avatar
Ghislain MARY committed
26 27
        private const string videoOn = "/Assets/AppBar/feature.video.png";
        private const string videoOff = "/Assets/AppBar/feature.video.png";
28

29 30
        private Timer oneSecondTimer;
        private Timer fadeTimer;
31
        private DateTimeOffset startTime;
32

33 34 35
        /// <summary>
        /// Public constructor.
        /// </summary>
36
        public InCall()
37
            : base(new InCallModel())
38 39
        {
            InitializeComponent();
40 41 42 43 44 45

            var call = LinphoneManager.Instance.LinphoneCore.GetCurrentCall();
            if (call != null && call.GetState() == Core.LinphoneCallState.StreamsRunning)
            {
                PauseStateChanged(false);
            }
46 47
        }

48 49 50 51
        /// <summary>
        /// Method called when the page is displayed.
        /// Searches for a matching contact using the current call address or number and display information if found.
        /// </summary>
52
        protected override void OnNavigatedTo(NavigationEventArgs nee)
53
        {
54
            // Create LinphoneCore if not created yet, otherwise do nothing
Sylvain Berfini's avatar
Sylvain Berfini committed
55
            LinphoneManager.Instance.InitLinphoneCore();
56

57 58 59
            base.OnNavigatedTo(nee);
            this.ViewModel.MuteListener = this;
            this.ViewModel.PauseListener = this;
60

61 62
            if (NavigationContext.QueryString.ContainsKey("sip"))
            {
63
                String calledNumber = NavigationContext.QueryString["sip"];
64 65 66 67
                if (calledNumber.StartsWith("sip:"))
                {
                    calledNumber = calledNumber.Substring(4);
                }
68
                // While we dunno if the number matches a contact one, we consider it won't and we display the phone number as username
69
                Contact.Text = calledNumber;
70

71 72 73 74 75 76
                if (calledNumber != null && calledNumber.Length > 0)
                {
                    ContactManager cm = ContactManager.Instance;
                    cm.ContactFound += cm_ContactFound;
                    cm.FindContact(calledNumber);
                }
77 78 79
            }
        }

80 81 82 83 84
        /// <summary>
        /// Method called when the page is leaved.
        /// </summary>
        protected override void OnNavigatedFrom(NavigationEventArgs nee)
        {
85
            if (oneSecondTimer != null)
86
            {
87 88 89 90 91 92
                oneSecondTimer.Dispose();
            }
            if (fadeTimer != null)
            {
                fadeTimer.Dispose();
                fadeTimer = null;
93 94
            }

95 96 97 98 99
            base.OnNavigatedFrom(nee);
            this.ViewModel.MuteListener = null;
            this.ViewModel.PauseListener = null;
        }

100 101 102
        /// <summary>
        /// Callback called when the search on a phone number for a contact has a match
        /// </summary>
103 104 105 106 107 108 109 110 111 112
        private void cm_ContactFound(object sender, ContactFoundEventArgs e)
        {
            Contact.Text = e.ContactFound.DisplayName;
            if (e.PhoneLabel != null)
            {
                Number.Text = e.PhoneLabel + " : " + e.PhoneNumber;
            }
            else
            {
                Number.Text = e.PhoneNumber;
113 114 115 116 117
            }
        }

        private void hangUp_Click(object sender, RoutedEventArgs e)
        {
118
            if (oneSecondTimer != null)
119
            {
120
                oneSecondTimer.Dispose();
121
            }
122
            LinphoneManager.Instance.EndCurrentCall();
123 124 125 126 127 128
        }

        private void speaker_Click_1(object sender, RoutedEventArgs e)
        {
            bool isSpeakerToggled = (bool)speaker.IsChecked;
            speakerImg.Source = new BitmapImage(new Uri(isSpeakerToggled ? speakerOn : speakerOff, UriKind.RelativeOrAbsolute));
Ghislain MARY's avatar
Ghislain MARY committed
129
            LinphoneManager.Instance.EnableSpeaker(isSpeakerToggled);
130 131 132 133 134
        }

        private void microphone_Click_1(object sender, RoutedEventArgs e)
        {
            bool isMicToggled = (bool)microphone.IsChecked;
135
            LinphoneManager.Instance.MuteMic(isMicToggled);
136 137 138 139 140

            if (isMicToggled)
                LinphoneManager.Instance.CallController.NotifyMuted();
            else
                LinphoneManager.Instance.CallController.NotifyUnmuted();
141 142
        }

143 144 145 146 147 148 149
        private void stats_Click_1(object sender, RoutedEventArgs e)
        {
            bool areStatsVisible = (bool)stats.IsChecked;
            emptyPanel.Visibility = areStatsVisible ? Visibility.Collapsed : Visibility.Visible;
            statsPanel.Visibility = areStatsVisible ? Visibility.Visible : Visibility.Collapsed;
        }

Ghislain MARY's avatar
Ghislain MARY committed
150 151 152 153 154 155 156 157 158 159
        private void video_Checked_1(object sender, RoutedEventArgs e)
        {
            bool isVideoToggled = (bool)video.IsChecked;
            videoImg.Source = new BitmapImage(new Uri(isVideoToggled ? videoOn : videoOff, UriKind.RelativeOrAbsolute));
            if (!LinphoneManager.Instance.EnableVideo(isVideoToggled))
            {
                if (isVideoToggled) video.IsChecked = false;
            }
        }

160 161 162 163 164
        /// <summary>
        /// Called when the mute status of the microphone changes.
        /// </summary>
        public void MuteStateChanged(Boolean isMicMuted)
        {
165
            microphone.IsChecked = isMicMuted;
166 167 168
            microImg.Source = new BitmapImage(new Uri(isMicMuted ? micOn : micOff, UriKind.RelativeOrAbsolute));
        }

169 170 171
        private void pause_Click_1(object sender, RoutedEventArgs e)
        {
            bool isPauseToggled = (bool)pause.IsChecked;
172 173 174 175
            if (isPauseToggled)
                LinphoneManager.Instance.PauseCurrentCall();
            else
                LinphoneManager.Instance.ResumeCurrentCall();
176 177
        }

178 179 180 181 182
        /// <summary>
        /// Called when the call changes its state to paused or resumed.
        /// </summary>
        public void PauseStateChanged(bool isCallPaused)
        {
183
            pause.IsChecked = isCallPaused;
184
            pauseImg.Source = new BitmapImage(new Uri(isCallPaused ? pauseOn : pauseOff, UriKind.RelativeOrAbsolute));
185

186
            if (!isCallPaused)
187
            {
188
                oneSecondTimer = new Timer(new TimerCallback(timerTick), null, 0, 1000);
189
            }
190
            else if (oneSecondTimer != null)
191
            {
192
                oneSecondTimer.Dispose();
193 194 195 196 197
            }
        }

        private void timerTick(Object state)
        {
198
            try
199
            {
200 201 202
                LinphoneCall call = LinphoneManager.Instance.LinphoneCore.GetCurrentCall();
                if (call == null)
                {
203
                    oneSecondTimer.Dispose();
204 205 206 207 208 209 210 211 212
                    return;
                }
                startTime = (DateTimeOffset)call.GetCallStartTimeFromContext();
                DateTimeOffset now = DateTimeOffset.Now;
                TimeSpan elapsed = now.Subtract(startTime);
                var ss = elapsed.Seconds;
                var mm = elapsed.Minutes;
                Status.Dispatcher.BeginInvoke(delegate()
                {
213
                    LinphoneCallParams param = call.GetCurrentParamsCopy();
214
                    Status.Text = mm.ToString("00") + ":" + ss.ToString("00");
215

216 217
                    LinphoneCallStats audioStats = call.GetAudioStats();
                    if (audioStats != null)
218
                    {
219 220
                        AudioDownBw.Text = String.Format(AppResources.StatDownloadBW + ": {0:0.00} kb/s", audioStats.GetDownloadBandwidth());
                        AudioUpBw.Text = String.Format(AppResources.StatUploadBW + ": {0:0.00} kb/s", audioStats.GetUploadBandwidth());
221 222
                    }

223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
                    PayloadType audiopt = param.GetUsedAudioCodec();
                    if (audiopt != null) 
                    {
                        AudioPType.Text = AppResources.StatPayload + ": " + audiopt.GetMimeType() + "/" + audiopt.GetClockRate();
                    }

                    if (call.IsCameraEnabled())
                    {
                        LinphoneCallStats videoStats = call.GetVideoStats();
                        if (videoStats != null)
                        {
                            VideoDownBw.Text = String.Format(AppResources.StatDownloadBW + ": {0:0.00} kb/s", videoStats.GetDownloadBandwidth());
                            VideoUpBw.Text = String.Format(AppResources.StatUploadBW + ": {0:0.00} kb/s", videoStats.GetUploadBandwidth());
                        }

                        PayloadType videopt = param.GetUsedVideoCodec();
                        if (videopt != null)
                        {
                            VideoPType.Text = AppResources.StatPayload + ": " + videopt.GetMimeType() + "/" + videopt.GetClockRate();
                        }

                        VideoStats.Visibility = Visibility.Visible;
                    }
                    else
247
                    {
248
                        VideoStats.Visibility = Visibility.Collapsed;
249
                    }
250

251
                    if (call.IsCameraEnabled() && !((InCallModel)ViewModel).IsVideoActive)
252
                    {
253 254
                        // Show video if it was not shown yet
                        ((InCallModel)ViewModel).IsVideoActive = true;
Ghislain MARY's avatar
Ghislain MARY committed
255
                        video.IsChecked = true;
256 257
                        ButtonsFadeInAnimation.Begin();
                        StartFadeTimer();
258 259 260 261 262
                    }
                    else if (!call.IsCameraEnabled() && ((InCallModel)ViewModel).IsVideoActive)
                    {
                        // Stop video if it is no longer active
                        ((InCallModel)ViewModel).IsVideoActive = false;
Ghislain MARY's avatar
Ghislain MARY committed
263
                        video.IsChecked = false;
264
                    }
265 266
                });
            } catch {
267
                oneSecondTimer.Dispose();
268
            }
269 270
        }

271 272
        private void dialpad_Click_1(object sender, RoutedEventArgs e)
        {
273
            ((InCallModel)ViewModel).ToggleDialpad();
274 275 276 277
        }

        private void Numpad_Click_1(object sender, RoutedEventArgs e)
        {
278 279 280
            Button button = sender as Button;
            String tag = button.Tag as String;
            LinphoneManager.Instance.LinphoneCore.SendDTMF(Convert.ToChar(tag));
281
        }
282

283 284 285 286 287 288 289 290 291 292
        private void remoteVideo_MediaOpened_1(object sender, System.Windows.RoutedEventArgs e)
        {
            Logger.Msg("RemoteVideo Opened: " + ((MediaElement)sender).Source.AbsoluteUri);
        }

        private void remoteVideo_MediaFailed_1(object sender, System.Windows.ExceptionRoutedEventArgs e)
        {
            Logger.Err("RemoteVideo Failed: " + e.ErrorException.Message);
        }

293 294 295 296 297 298 299 300 301 302
        private void localVideo_MediaOpened_1(object sender, System.Windows.RoutedEventArgs e)
        {
            Logger.Msg("LocalVideo Opened: " + ((MediaElement)sender).Source.AbsoluteUri);
        }

        private void localVideo_MediaFailed_1(object sender, System.Windows.ExceptionRoutedEventArgs e)
        {
            Logger.Err("LocalVideo Failed: " + e.ErrorException.Message);
        }

303 304 305 306 307 308 309
        /// <summary>
        /// Do not allow user to leave the incall page while call is active
        /// </summary>
        protected override void OnBackKeyPress(CancelEventArgs e)
        {
            e.Cancel = true;
        }
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346

        private void ButtonsFadeOutAnimation_Completed(object sender, EventArgs e)
        {
            buttons.Visibility = Visibility.Collapsed;
            statsPanel.Visibility = Visibility.Collapsed;
            Status.Visibility = Visibility.Collapsed;
            Contact.Visibility = Visibility.Collapsed;
            Number.Visibility = Visibility.Collapsed;
        }

        private void HideButtons(Object state)
        {
            Status.Dispatcher.BeginInvoke(delegate()
            {
                ButtonsFadeOutAnimation.Begin();
            });
        }

        private void StartFadeTimer()
        {
            if (fadeTimer != null)
            {
                fadeTimer.Dispose();
            }
            fadeTimer = new Timer(new TimerCallback(HideButtons), null, 4000, Timeout.Infinite);
        }

        private void LayoutRoot_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            buttons.Visibility = Visibility.Visible;
            statsPanel.Visibility = ((bool)stats.IsChecked) ? Visibility.Visible : Visibility.Collapsed;
            Status.Visibility = Visibility.Visible;
            Contact.Visibility = Visibility.Visible;
            Number.Visibility = Visibility.Visible;
            ButtonsFadeInAnimation.Begin();
            StartFadeTimer();
        }
347 348
    }
}