d9b939ef6facce7328c4445d560ebbfbcf16d882
[apps/osp/Call.git] / src / CallSoundManager.cpp
1 //
2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
3 //
4 // Licensed under the Flora License, Version 1.1 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://floralicense.org/license/
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 /**
18  * @file    CallSettingsMoreOptionsForm.cpp
19  * @brief   Sound manager class
20  */
21 #include "CallSoundManager.h"
22
23 using namespace Tizen::Base;
24 using namespace Tizen::Graphics;
25 using namespace Tizen::Io;
26 using namespace Tizen::Media;
27 using namespace Tizen::Social;
28 using namespace Tizen::System;
29 using namespace Tizen::Base::Collection;
30 using namespace Tizen::Base::Runtime;
31
32 static const wchar_t* RINGTONE_PATH = L"/opt/usr/apps/zktdpemtmw/shared/data/ringtone_sdk.mp3";
33 static const wchar_t* CALLCONNECTTONE_PATH = L"/opt/usr/apps/zktdpemtmw/shared/data/Call_Connect.ogg";
34 static const wchar_t* CALLDISCONNECTTONE_PATH = L"/opt/usr/apps/zktdpemtmw/shared/data/Call_Disconnect.ogg";
35 static const wchar_t* MINUTEREMINDERTONE_PATH = L"/opt/usr/apps/zktdpemtmw/shared/data/Call_RecordStart.wav";
36 static const wchar_t* CALLWAITINGTONE_PATH = L"/opt/usr/apps/zktdpemtmw/shared/data/Call_WaitingTone.wav";
37
38
39 SoundManager::SoundManager(void)
40         : __pSoundCallSession(null)
41         , __pVibrator(null)
42         , __pPlayer(null)
43         , __lastEndedConferenceCall(false)
44         , __pConnectPlayer(null)
45         , __pDisconnectPlayer(null)
46         , __pReminderPlayer(null)
47         , __pWaitingTonePlayer(null)
48 {
49         __timer.Construct(*this);
50         __isSoundStatusOn = false;
51         __isVibrateStatusOn = false;
52 }
53
54 SoundManager::~SoundManager(void)
55 {
56         if(__pSoundCallSession != null)
57         {
58                 sound_manager_call_session_destroy(__pSoundCallSession);
59         }
60         if (__pVibrator != null)
61         {
62                 delete __pVibrator;
63                 __pVibrator = null;
64         }
65         if (__pPlayer != null)
66         {
67                 delete __pPlayer;
68                 __pPlayer = null;
69         }
70         if(__pConnectPlayer != null)
71         {
72                 delete __pConnectPlayer;
73                 __pConnectPlayer = null;
74         }
75         if(__pDisconnectPlayer != null)
76         {
77                 delete __pDisconnectPlayer;
78                 __pDisconnectPlayer = null;
79         }
80         if(__pReminderPlayer != null)
81         {
82                 delete __pReminderPlayer;
83                 __pReminderPlayer = null;
84         }
85         if(__pWaitingTonePlayer != null)
86         {
87                 delete __pWaitingTonePlayer;
88                 __pWaitingTonePlayer = null;
89         }
90
91 }
92
93 void
94 SoundManager::SetlastEndedConferenceCall()
95 {
96         __lastEndedConferenceCall = true;
97 }
98
99 bool
100 SoundManager::GetLastConferenceCall()
101 {
102         return __lastEndedConferenceCall;
103 }
104
105 Timer*
106 SoundManager::GetTimer()
107 {
108         return &__timer;
109 }
110
111 result
112 SoundManager::StopSession(void)
113 {
114         AppLogDebug("Enter");
115         if(__pSoundCallSession != null)
116         {
117                 AppLogDebug("sound_manager_call_session_destroy");
118                 sound_manager_call_session_destroy(__pSoundCallSession);
119                 __pSoundCallSession = null;
120         }
121
122         return E_SUCCESS;
123 }
124
125 result
126 SoundManager::StartSession(void)
127 {
128         AppLogDebug("Enter");
129         if (__pSoundCallSession != null)
130         {
131                 sound_manager_call_session_set_mode(__pSoundCallSession,(sound_call_session_mode_e)SOUND_CALL_SESSION_MODE_VOICE);
132                 sound_manager_set_active_route((sound_route_e)SOUND_ROUTE_IN_MIC_OUT_RECEIVER);
133                 sound_manager_set_volume((sound_type_e)SOUND_TYPE_CALL,5);
134                 return E_SUCCESS;
135         }
136         int res = sound_manager_call_session_create((sound_call_session_type_e)SOUND_SESSION_TYPE_CALL, &__pSoundCallSession);
137         if (res != SOUND_MANAGER_ERROR_NONE)
138         {
139                 AppLogDebug("Sound manager creation failed");
140                 return E_FAILURE;
141         }
142         res = sound_manager_call_session_set_mode(__pSoundCallSession,(sound_call_session_mode_e)SOUND_CALL_SESSION_MODE_VOICE);
143         sound_manager_set_active_route((sound_route_e)SOUND_ROUTE_IN_MIC_OUT_RECEIVER);
144         //todo start listening for volume key and set the volume
145         sound_manager_set_volume((sound_type_e)SOUND_TYPE_CALL,5);
146         return E_SUCCESS;
147 }
148
149 result
150 SoundManager::SetSpeakerStatus(bool setSpeaker)
151 {
152         result r = E_FAILURE;
153         int res = -1;
154         bool isEarJackPresent = IsEarJackConnected();
155         sound_route_e soundRoute;
156         if (setSpeaker == true)
157         {
158                 soundRoute = SOUND_ROUTE_IN_MIC_OUT_SPEAKER;
159         }
160         else
161         {
162                 if (isEarJackPresent == true)
163                 {
164                         soundRoute = SOUND_ROUTE_IN_MIC_OUT_HEADPHONE;
165                 }
166                 else
167                 {
168                         soundRoute = SOUND_ROUTE_IN_MIC_OUT_RECEIVER;
169                 }
170         }
171         res = sound_manager_set_active_route(soundRoute);
172         if (res == SOUND_MANAGER_ERROR_NONE)
173         {
174                 r = E_SUCCESS;
175         }
176         else
177         {
178                 r = E_FAILURE;
179         }
180         return r;
181 }
182
183 result
184 SoundManager::SetSoundMode(SoundMode soundMode)
185 {
186         if (__pSoundCallSession == null)
187         {
188                 return E_FAILURE;
189         }
190         sound_call_session_mode_e sessionMode;
191         switch (soundMode)
192         {
193         case SOUND_MODE_RINGTONE:
194         {
195                 sessionMode = SOUND_CALL_SESSION_MODE_RINGTONE;
196                 break;
197         }
198         case SOUND_MODE_MEDIA:
199         {
200                 sessionMode = SOUND_CALL_SESSION_MODE_MEDIA;
201                 break;
202         }
203         case SOUND_MODE_VOICE:
204         {
205                 sessionMode = SOUND_CALL_SESSION_MODE_VOICE;
206         }
207         break;
208         default:
209         {
210                 sessionMode = SOUND_CALL_SESSION_MODE_RINGTONE;
211                 break;
212         }
213         }
214         int res = sound_manager_call_session_set_mode(__pSoundCallSession,sessionMode);
215         if (res != SOUND_MANAGER_ERROR_NONE)
216         {
217                 return E_FAILURE;
218         }
219         return E_SUCCESS;
220 }
221
222 void
223 SoundManager::OnTimerExpired(Timer& timer)
224 {
225         String reminderTonePath;
226         int unknownRejectStatus = -1;
227         vconf_get_bool(VCONFKEY_CISSAPPL_MINUTE_MINDER_BOOL, &unknownRejectStatus);
228         bool ReminderToneSetStatus = unknownRejectStatus;
229         result res = E_FAILURE;
230         reminderTonePath.Append(MINUTEREMINDERTONE_PATH);
231
232         if(ReminderToneSetStatus == true)
233         {
234
235                 if(__pReminderPlayer == null)
236                 {
237
238                         if(reminderTonePath.IsEmpty() == false)
239                         {
240                                 __pReminderPlayer =  new (std::nothrow) Player();
241                                 res = __pReminderPlayer->Construct(*this);
242                                 if(res != E_SUCCESS)
243                                 {
244                                         AppLogDebug("__pReminderPlayer Construct failed with %d",res);
245                                         delete __pReminderPlayer;
246                                         __pReminderPlayer = null;
247                                         return;
248                                 }
249                                 res = __pReminderPlayer->OpenFile(reminderTonePath,false);
250                                 if(res != E_SUCCESS)
251                                 {
252                                         AppLogDebug("__pReminderPlayer OpenFile failed with %d",res);
253                                         delete __pReminderPlayer;
254                                         __pReminderPlayer = null;
255                                         return;
256                                 }
257                                 res = __pReminderPlayer->SetLooping(false);
258                                 if(res != E_SUCCESS)
259                                 {
260                                         AppLogDebug("__pReminderPlayer SetLooping failed with %d",res);
261                                         delete __pReminderPlayer;
262                                         __pReminderPlayer = null;
263                                         return;
264                                 }
265                                 res = __pReminderPlayer->SetVolume(80);
266                                 if(res != E_SUCCESS)
267                                 {
268                                         AppLogDebug("__pReminderPlayer SetVolume failed with %d",res);
269                                         delete __pReminderPlayer;
270                                         __pReminderPlayer = null;
271                                         return;
272                                 }
273                         }
274                 }
275
276                 if(__pReminderPlayer != null)
277                 {
278                         SetSoundMode(SOUND_MODE_MEDIA);
279                         res = __pReminderPlayer->Play();
280                         if(res != E_SUCCESS)
281                         {
282                                 AppLogDebug("__pReminderPlayer Play failed with %d",res);
283                                 return;
284                         }
285                         SetSoundMode(SOUND_MODE_VOICE);
286                 }
287         }
288         /*else if(ReminderToneSetStatus == false)
289         {
290                 timer.Cancel();
291         }*/
292
293 }
294
295
296
297 void
298 SoundManager::SetDisconnectTone(void)
299 {
300
301         AppLogDebug("Enter");
302         int unknownRejectStatus = -1;
303         String disconnectTonePath=L"";
304         vconf_get_bool(VCONFKEY_CISSAPPL_CALL_END_TONE_BOOL, &unknownRejectStatus);
305         bool disconnectToneSetStatus = unknownRejectStatus;
306         result res = E_FAILURE;
307
308         if(disconnectToneSetStatus == true)
309         {
310                 AppLogDebug("disconnectToneSetStatus == true");
311                 disconnectTonePath.Append(CALLDISCONNECTTONE_PATH);
312                 if(disconnectTonePath.IsEmpty() == false)
313                 {
314                         if(__pDisconnectPlayer == null)
315                         {
316                                 AppLogDebug("__pConnectPlayer == null");
317                                 __pDisconnectPlayer =  new (std::nothrow) Player();
318                                 res = __pDisconnectPlayer->Construct(*this);
319                                 if(res != E_SUCCESS)
320                                 {
321                                         AppLogDebug("__pDisconnectPlayer Construct failed with %d",res);
322                                         delete __pDisconnectPlayer;
323                                         __pDisconnectPlayer = null;
324                                         return;
325                                 }
326                                 res = __pDisconnectPlayer->OpenFile(disconnectTonePath,false);
327                                 if(res != E_SUCCESS)
328                                 {
329                                         AppLogDebug("__pDisconnectPlayer OpenFile failed with %d",res);
330                                         delete __pDisconnectPlayer;
331                                         __pDisconnectPlayer = null;
332                                         return;
333                                 }
334                                 res = __pDisconnectPlayer->SetLooping(false);
335                                 if(res != E_SUCCESS)
336                                 {
337                                         AppLogDebug("__pDisconnectPlayer SetLooping failed with %d",res);
338                                         delete __pDisconnectPlayer;
339                                         __pDisconnectPlayer = null;
340                                         return;
341                                 }
342                                 res = __pDisconnectPlayer->SetVolume(80);
343                                 if(res != E_SUCCESS)
344                                 {
345                                         AppLogDebug("__pDisconnectPlayer SetLooping SetVolume with %d",res);
346                                         delete __pDisconnectPlayer;
347                                         __pDisconnectPlayer = null;
348                                         return;
349                                 }
350
351                         }
352                 }
353
354                 if(__pDisconnectPlayer != null)
355                 {
356                         AppLogDebug("__pDisconnectPlayer OpenFile %ls",disconnectTonePath.GetPointer());
357                         SetSoundMode(SOUND_MODE_MEDIA);
358                         AppLogDebug("__pDisconnectPlayer SetVolume");
359                         if(__pDisconnectPlayer->GetState() == PLAYER_STATE_PLAYING)
360                         {
361                                 __pDisconnectPlayer->Stop();
362                         }
363                         res = __pDisconnectPlayer->Play();
364                         if(res != E_SUCCESS)
365                         {
366                                 AppLogDebug("__pDisconnectPlayer Play with %d",res);
367                                 return;
368                         }
369                 }
370
371         }
372
373
374
375
376         AppLogDebug("Exit");
377
378 }
379
380 void
381 SoundManager::SetMinuteReminderTone(void)
382 {
383         __timer.StartAsRepeatable(60000);
384 }
385
386
387 void
388 SoundManager::SetConnectTone(void)
389 {
390
391         String connectTonePath;
392         int unknownRejectStatus = -1;
393         vconf_get_bool(VCONFKEY_CISSAPPL_CALL_CONNECT_TONE_BOOL, &unknownRejectStatus);
394         bool connectToneSetStatus = unknownRejectStatus;
395         result res = E_FAILURE;
396
397         connectTonePath.Append(CALLCONNECTTONE_PATH);
398
399         if(connectToneSetStatus == true)
400         {
401
402                 if(__pConnectPlayer == null)
403                 {
404                         if (connectTonePath.IsEmpty() == false)
405                         {
406                                 __pConnectPlayer =  new (std::nothrow) Player();
407                                 res = __pConnectPlayer->Construct(*this);
408                                 if(res != E_SUCCESS)
409                                 {
410                                         AppLogDebug("__pConnectPlayer Construct failed with %d",res);
411                                         delete __pConnectPlayer;
412                                         __pConnectPlayer = null;
413                                         return;
414                                 }
415                                 res = __pConnectPlayer->OpenFile(connectTonePath,false);
416                                 if(res != E_SUCCESS)
417                                 {
418                                         AppLogDebug("__pConnectPlayer OpenFile failed with %d",res);
419                                         delete __pConnectPlayer;
420                                         __pConnectPlayer = null;
421                                         return;
422                                 }
423                                 res = __pConnectPlayer->SetLooping(false);
424                                 if(res != E_SUCCESS)
425                                 {
426                                         AppLogDebug("__pConnectPlayer SetLooping failed with %d",res);
427                                         delete __pConnectPlayer;
428                                         __pConnectPlayer = null;
429                                         return;
430                                 }
431                                 res = __pConnectPlayer->SetVolume(80);
432                                 if(res != E_SUCCESS)
433                                 {
434                                         AppLogDebug("__pConnectPlayer SetVolume failed with %d",res);
435                                         delete __pConnectPlayer;
436                                         __pConnectPlayer = null;
437                                         return;
438                                 }
439                         }
440                 }
441
442                 if(__pConnectPlayer != null)
443                 {
444                         res = SetSoundMode(SOUND_MODE_MEDIA);
445                         AppLogDebug("__pConnectPlayer Playing connect tone");
446                         res = __pConnectPlayer->Play();
447                         if(res != E_SUCCESS)
448                         {
449                                 AppLogDebug("__pConnectPlayer Play failed with %d",res);
450                                 return;
451                         }
452                 }
453
454         }
455
456
457 }
458
459 void
460 SoundManager::SetWaitTone(void)
461 {
462         CallAlertStatus status= CALL_ALERT_SOUND;
463         int alertStatus = -1;
464         result res = E_FAILURE;
465         int retVal = vconf_get_int(VCONFKEY_CISSAPPL_ALERT_ON_CALL_INT, &alertStatus);
466         if (retVal == 0)
467         {
468                 status = (CallAlertStatus) alertStatus;
469         }
470         AppLogDebug("No Alert already in call");
471         if(status == CALL_ALERT_SOUND)
472         {
473                 AppLogDebug("Playing alert tone");
474                 String waitingTonePath;
475                 waitingTonePath.Append(CALLWAITINGTONE_PATH);
476                 if(__pWaitingTonePlayer == null)
477                 {
478                         if (waitingTonePath.IsEmpty() == false)
479                         {
480                                 __pWaitingTonePlayer =  new (std::nothrow) Player();
481                                 res = __pWaitingTonePlayer->Construct(*this);
482                                 if(res != E_SUCCESS)
483                                 {
484                                         AppLogDebug("__pWaitingTonePlayer Construct failed with %d",res);
485                                         delete __pWaitingTonePlayer;
486                                         __pWaitingTonePlayer = null;
487                                         return;
488                                 }
489                                 res = __pWaitingTonePlayer->OpenFile(waitingTonePath,false);
490                                 if(res != E_SUCCESS)
491                                 {
492                                         AppLogDebug("__pWaitingTonePlayer OpenFile failed with %d",res);
493                                         delete __pWaitingTonePlayer;
494                                         __pWaitingTonePlayer = null;
495
496                                         return;
497                                 }
498                                 res = __pWaitingTonePlayer->SetLooping(true);
499                                 if(res != E_SUCCESS)
500                                 {
501                                         AppLogDebug("__pWaitingTonePlayer SetLooping failed with %d",res);
502                                         delete __pWaitingTonePlayer;
503                                         __pWaitingTonePlayer = null;
504
505                                         return;
506                                 }
507                                 res = __pWaitingTonePlayer->SetVolume(80);
508                                 if(res != E_SUCCESS)
509                                 {
510                                         AppLogDebug("__pWaitingTonePlayer SetVolume failed with %d",res);
511                                         delete __pWaitingTonePlayer;
512                                         __pWaitingTonePlayer = null;
513
514                                         return;
515                                 }
516                         }
517                 }
518
519                 if( __pWaitingTonePlayer != null )
520                 {
521                         SetSoundMode(SOUND_MODE_MEDIA);
522                         res = __pWaitingTonePlayer->Play();
523                         if(res != E_SUCCESS)
524                         {
525                                 AppLogDebug("__pWaitingTonePlayer Play failed with %d",res);
526                                 return;
527                         }
528                 }
529
530         }
531 }
532
533 void
534 SoundManager::StartAlert(String& contactRingTone)
535 {
536         result res = E_FAILURE;
537         IntensityDurationVibrationPattern vibration;
538         vibration.duration = 3000;
539         vibration.intensity = -1;
540         AppLogDebug("Enter");
541         if(__pSoundCallSession != null)
542         {
543                 SetWaitTone();
544                 return;
545         }
546         else
547         {
548                 StartSession();
549         }
550         if(__pVibrator == null)
551         {
552                 __pVibrator = new (std::nothrow) Vibrator();
553                 res = __pVibrator->Construct();
554                 if(res != E_SUCCESS)
555                 {
556                         AppLogDebug("__pVibrator Construct failed with %d",res);
557                         return;
558                 }
559         }
560         if(__pPlayer == null)
561         {
562                 __pPlayer =  new (std::nothrow) Player();
563                 res = __pPlayer->Construct(*this);
564                 if(res != E_SUCCESS)
565                 {
566                         AppLogDebug("__pPlayer Construct failed with %d",res);
567                         delete __pPlayer;
568                         __pPlayer = null;
569                         return;
570                 }
571         }
572         int retVal = -1;
573         vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &retVal);
574         __isSoundStatusOn = retVal;
575         vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &retVal);
576         __isVibrateStatusOn = retVal;
577         //todo: do only if call alert mode is set
578         if (__isSoundStatusOn == true)
579         {
580                 String ringTonePath;
581                 //Check if contact has any custom ringtone, else play defautl ringtone.
582                 if(contactRingTone.IsEmpty() == true)
583                 {
584                         char* pRingTonePtr = vconf_get_str(VCONFKEY_SETAPPL_CALL_RINGTONE_PATH_STR);
585                         AppLog("Ringtone Path : %s",pRingTonePtr);
586                         ringTonePath.Append(pRingTonePtr);
587                 }
588                 else
589                 {
590                         AppLog("Ringtone Path : %ls",contactRingTone.GetPointer());
591                         ringTonePath.Append(contactRingTone);
592                 }
593
594                 //Check if file is present
595                 File file;
596                 res = file.Construct(ringTonePath, "r");
597                 if(res != E_SUCCESS )
598                 {
599                         ringTonePath.Clear();
600                         ringTonePath.Append(RINGTONE_PATH);
601                 }
602
603                 res = __pPlayer->OpenFile(ringTonePath,false);
604                 if(res != E_SUCCESS)
605                 {
606                         AppLogDebug("__pPlayer Construct failed with %d",res);
607                         return;
608                 }
609                 res = __pPlayer->SetLooping(true);
610                 if(res != E_SUCCESS)
611                 {
612                         AppLogDebug("__pPlayer Construct failed with %d",res);
613                         return;
614                 }
615                 res = __pPlayer->SetVolume(80);
616                 if(res != E_SUCCESS)
617                 {
618                         AppLogDebug("__pPlayer Construct failed with %d",res);
619                         return;
620                 }
621                 res = SetSoundMode(SOUND_MODE_RINGTONE);
622                 res = __pPlayer->Play();
623                 if(res != E_SUCCESS)
624                 {
625                         AppLogDebug("__pPlayer Construct failed with %d",res);
626                         return;
627                 }
628         }
629         if (__isVibrateStatusOn == true)
630         {
631                 //todo: Get the level from settings
632                 __pVibrator->Start(&vibration, 1, 1000);
633         }
634         AppLogDebug("Exit");
635         return;
636 }
637
638 void
639 SoundManager::StopAlert(void)
640 {
641         result res = E_FAILURE;
642         AppLogDebug("Enter");
643         if (__isSoundStatusOn == true)
644         {
645                 //todo: stop player
646                 if(__pPlayer != null)
647                 {
648                         AppLogDebug("Stopping ring tone");
649                         if(__pPlayer->GetState() == PLAYER_STATE_PLAYING)
650                         {
651                                 res = __pPlayer->Stop();
652                         }
653                         if(res != E_SUCCESS)
654                         {
655                                 AppLogDebug("__pPlayer Stop failed with %d",res);
656                                 return;
657                         }
658                         res = __pPlayer->Close();
659                         if(res != E_SUCCESS)
660                         {
661                                 AppLogDebug("__pPlayer Close failed with %d",res);
662                                 return;
663                         }
664                         SetSoundMode(SOUND_MODE_VOICE);
665                         __isSoundStatusOn = false;
666                         StopSession();
667                 }
668         }
669         if (__isVibrateStatusOn == true)
670         {
671                 __pVibrator->Stop();
672                 __isVibrateStatusOn = false;
673         }
674         if(__pWaitingTonePlayer != null)
675         {
676                 if(__pWaitingTonePlayer->GetState() == PLAYER_STATE_PLAYING)
677                 {
678                         __pWaitingTonePlayer->Stop();
679                 }
680         }
681
682         AppLogDebug("Exit");
683 }
684
685 void
686 SoundManager::OnPlayerOpened(result r)
687 {
688 }
689
690 void
691 SoundManager::OnPlayerEndOfClip(void)
692 {
693 }
694
695 void
696 SoundManager::OnPlayerSeekCompleted(result r)
697 {
698 }
699
700 void
701 SoundManager::OnPlayerBuffering(int percent)
702 {
703 }
704
705 void
706 SoundManager::OnPlayerErrorOccurred(Tizen::Media::PlayerErrorReason r)
707 {
708 }
709
710 void
711 SoundManager::OnPlayerInterrupted(void)
712 {
713 }
714
715 void
716 SoundManager::OnPlayerReleased(void)
717 {
718 }
719
720 bool
721 SoundManager::IsEarJackConnected(void)
722 {
723         int earJackStatus = -1;
724         if (vconf_get_int(VCONFKEY_SYSMAN_EARJACK, &earJackStatus) == 0)
725         {
726                 if (earJackStatus == VCONFKEY_SYSMAN_EARJACK_REMOVED)
727                 {
728                         return false;
729                 }
730                 else
731                 {
732                         return true;
733                 }
734         }
735         else
736         {
737                 return false;
738         }
739 }