فهرست منبع

Client <-> Pro video call - e2e working version [WIP]

Vijayakrishnan 5 سال پیش
والد
کامیت
ded0d358c1
5فایلهای تغییر یافته به همراه121 افزوده شده و 32 حذف شده
  1. 9 0
      app/Http/Controllers/ProController.php
  2. 12 2
      public/css/meeting.css
  3. 11 8
      resources/views/mc.blade.php
  4. 88 22
      resources/views/meet.blade.php
  5. 1 0
      routes/web.php

+ 9 - 0
app/Http/Controllers/ProController.php

@@ -6,6 +6,7 @@ use App\Models\Meeting;
 use App\Models\MeetingParticipant;
 use Illuminate\Http\Request;
 use App\Models\Pro;
+use Illuminate\Support\Facades\DB;
 
 class ProController extends Controller
 {
@@ -49,4 +50,12 @@ class ProController extends Controller
             'guest' => false
         ]);
     }
+
+    public function getOpentokSessionKey(Request $request, $uid) {
+        $client = DB::table('client')->where('uid', $uid)->first();
+        return json_encode([
+            "data" => $client->video_visit_tokbox_token
+        ]);
+    }
+
 }

+ 12 - 2
public/css/meeting.css

@@ -87,15 +87,18 @@ h1 {
 .main-view {
     width: 800px;
     height: 600px;
+    max-width: 100%;
+    max-height: 100%;
     margin: 0 1rem;
-    background: #444;
-    border-radius: 3px;
     position: relative;
 }
 
 .main-view .full-view {
     width: 100%;
     height: 100%;
+    background: #444;
+    border-radius: 3px;
+    margin: 0 auto;
 }
 .main-view .thumb-view {
     position: absolute;
@@ -145,3 +148,10 @@ h1 {
     text-overflow: ellipsis;
     overflow: hidden;
 }
+
+.btn[disabled] {
+    opacity: 0.3;
+}
+body .OT_fit-mode-cover .OT_video-element {
+    object-fit: contain;
+}

+ 11 - 8
resources/views/mc.blade.php

@@ -7,22 +7,25 @@
     <meta http-equiv="X-UA-Compatible" content="ie=edge">
     <!-- CSRF Token -->
     <meta name="csrf-token" content="{{ csrf_token() }}">
-    <script src="{{ mix('js/app.js') }}" defer></script>
+    {{--<script src="{{ mix('js/app.js') }}" defer></script>--}}
     <link rel="stylesheet" href="/css/bootstrap.min.css">
-    <link href="{{ mix('css/app.css') }}" rel="stylesheet">
-    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">
+    {{--<link href="{{ mix('css/app.css') }}" rel="stylesheet">--}}
+    {{--<link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">--}}
     <title>Meeting Center</title>
 </head>
-<body class="d-flex align-items-stretch h-100 mc-page">
-    <div class="row w-100">
-        <div class="col-9 pr-0 app-left-panel">
+<body class="h-100 mc-page">
+    <div class="row mx-0 h-100">
+        <div class="col-9 px-0 app-left-panel">
             <iframe src="{{ $page }}" frameborder="0" class="h-100 w-100"></iframe>
         </div>
-        <div id="meetingsApp" class="pro col-3 border-left app-right-panel">
-            <meetings-app-root 
+        {{--<div id="meetingsApp" class="pro col-3 border-left app-right-panel">
+            <meetings-app-root
                 :user-prop="{!! str_replace('"','\'',str_replace('\'','\\\'',json_encode($user))) !!}"
                 :meeting-prop="{!! str_replace('"','\'',str_replace('\'','\\\'',json_encode($meeting))) !!}"
                 ></meetings-app-root>
+        </div>--}}
+        <div class="col-3 border-left app-right-panel pr-1">
+            <iframe src="/pro/meet" frameborder="0" class="h-100 w-100"></iframe>
         </div>
     </div>
     <script src="/AdminLTE-3.0.5/plugins/jquery/jquery.min.js"></script>

+ 88 - 22
resources/views/meet.blade.php

@@ -3,7 +3,7 @@
 
     <div id="meetComponent">
 
-        <h5 class="bg-dark font-weight-bold text-white m-0 py-3 px-4 d-flex">
+        {{--<h5 class="bg-dark font-weight-bold text-white m-0 py-3 px-4 d-flex">
             <span>Meeting</span>
             <span class="ml-auto" v-if="!started">
                 Connecting...
@@ -12,17 +12,26 @@
                 <i class="fa fa-clock mr-1 text-light"></i>
                 @{{ timeDisplay() }}
             </span>
-        </h5>
+        </h5>--}}
 
-        <div class="mt-4">
+        @if(!$guest)
+            <div class="d-flex align-items-center justify-content-center py-2">
+                <button class="btn btn-sm btn-primary px-4 font-weight-bold"
+                        v-on:click.prevent="nextPatient()"
+                        :disabled="client || checkingForNextPatient">Next Patient</button>
+            </div>
+            <div v-if="noNextPatient" class="bg-light rounded text-center py-1 font-weight-bold text-sm">@{{ noNextPatient }}</div>
+        @endif
+
+        <div class="">
             @if($guest)
-            <div class="py-2 text-center" v-if="!pro">
-                <h6 class="text--black font-weight-bold">Please wait. Your doctor will be with you shortly...</h6>
+            <div class="py-3 text-center" v-if="!pro">
+                <h6 class="text--black font-weight-bold m-0">Please wait. Your doctor will be with you shortly...</h6>
             </div>
             @endif
             <div class="main-view mx-auto">
-                <div id="self-view" class="full-view"></div>
-                <div id="remote-view" class="thumb-view"></div>
+                <div id="self-view" class="<?= $guest ? 'full-view' : 'd-none' ?>"></div>
+                <div <?= !$guest ? 'v-show="!!client"' : '' ?> id="remote-view" class="<?= $guest ? 'thumb-view' : 'full-view' ?>"></div>
             </div>
         </div>
 
@@ -49,8 +58,43 @@
                 @endif
 
                 otSessionId: '',
+
+                @if(!$guest)
+                checkingForNextPatient: false,
+                noNextPatient: false,
+                @endif
+
+                otSession: false,
             },
             methods: {
+                nextPatient: function() {
+                    var self = this;
+                    this.checkingForNextPatient = true;
+                    $.post('/api/client/getNextClientForVideoVisit', {}, function(_data) {
+                        self.checkingForNextPatient = false;
+                        if(!_data.success) {
+                            self.noNextPatient = _data.message;
+                            window.setTimeout(function() {
+                                self.noNextPatient = false;
+                            }, 2000);
+                        }
+                        else {
+                            // get ot session key from client record
+                            self.client = true;
+                            self.clientUid = _data.data;
+                            self.getOpenTokSessionId(function() {
+                                self.selfName = 'Pro'; // TODO: replace with name of authed pro
+                                $.post('/api/openTok/getClientToken', {
+                                    opentokSessionId: self.otSessionId,
+                                    name: self.selfName
+                                }, function (_data) {
+                                    self.selfToken = _data.data;
+                                    self.initOpenTok();
+                                });
+                            });
+                        }
+                    }, 'json');
+                },
                 getInitials: function(_name) {
                     var parts = _name.split(/\s+/g);
                     parts = parts.map(_part => _part[0]);
@@ -96,32 +140,48 @@
                     canvas.height = 480;
                     const ctx = canvas.getContext('2d');
 
-                    const x = randomColour();
-                    ctx.clearRect(0, 0, canvas.width, canvas.height);
-                    ctx.font = "20px Georgia";
-                    ctx.fillStyle = `rgb(220, 220, 220)`;
-                    var userType = '<?= $guest? "Client" : "Pro" ?>';
-                    ctx.fillText("Video feed from the " + userType, 20, 100);
+                    var pos = 100;
+                    window.setInterval(function() {
+                        ctx.clearRect(0, 0, canvas.width, canvas.height);
+                        ctx.font = "20px Georgia";
+                        ctx.fillStyle = `rgb(220, 220, 220)`;
+                        var userType = '<?= $guest? "Client" : "Pro" ?>';
+                        ctx.fillText("Video feed from the " + userType, 20, pos);
+                        pos += 5;
+                        if(pos > canvas.height) pos = 100;
+                    }, 1000);
 
                     var self = this;
 
-                    var apiKey = '46678902';
+                    var apiKey = '46794204';
                     var sessionId = this.otSessionId;
                     var token = this.selfToken;
-                    var session = OT.initSession(apiKey, sessionId);
 
-                    // TODO: Subscribe to remote stream (pro)
-                    session.on('streamCreated', function streamCreated(event) {
+                    // destroy if existing
+                    if(self.otSession) {
+                        self.otSession.disconnect();
+                        self.otSession = '';
+                    }
+
+                    self.otSession = OT.initSession(apiKey, sessionId);
+
+                    // TODO: Subscribe to remote stream
+                    self.otSession.on('streamCreated', function streamCreated(event) {
                         console.log(event);
                         var subscriberOptions = {
                             insertMode: 'append',
                             width: '100%',
                             height: '100%'
                         };
-                        session.subscribe(event.stream, 'subscriber', subscriberOptions, handleError);
+                        self.otSession.subscribe(event.stream, 'remote-view', subscriberOptions, self.handleOpenTokError);
+
+                        @if($guest)
+                        $('#self-view').removeClass('full-view').addClass('thumb-view');
+                        $('#remote-view').removeClass('thumb-view').addClass('full-view');
+                        @endif
                     });
 
-                    session.on('sessionDisconnected', function sessionDisconnected(event) {
+                    self.otSession.on('sessionDisconnected', function sessionDisconnected(event) {
                         console.log('You were disconnected from the session.', event.reason);
                     });
 
@@ -135,12 +195,12 @@
                     var publisher = OT.initPublisher('self-view', publisherOptions, self.handleOpenTokError);
 
                     // Connect to the session
-                    session.connect(token, function callback(error) {
+                    self.otSession.connect(token, function callback(error) {
                         if (error) {
                             self.handleOpenTokError(error);
                         } else {
                             // If the connection is successful, publish the publisher to the session
-                            session.publish(publisher, self.handleOpenTokError);
+                            self.otSession.publish(publisher, self.handleOpenTokError);
                         }
                     });
                 },
@@ -159,6 +219,7 @@
                 getOpenTokSessionId: function(_done) {
                     var self = this;
 
+                    @if($guest)
                     $.ajax({
                         type: 'post',
                         url: '/api/clientVideoVisit/startVideoVisitAsStranger',
@@ -182,7 +243,12 @@
                             console.log(_data);
                             alert(_data.message);
                         });
-
+                    @else
+                    $.get('/pro/get-opentok-session-key/' + self.clientUid, function(_data) {
+                        self.otSessionId = _data.data;
+                        _done();
+                    }, 'json');
+                    @endif
                 }
             },
             mounted: function() {

+ 1 - 0
routes/web.php

@@ -52,6 +52,7 @@ Route::middleware('ensureValidProSession')->group(function(){
 //    Route::get("/pros/show/{uid}", 'ProController@show')->name('pro-show');
 
     Route::get('/pro/meet', 'ProController@meet');
+    Route::get('/pro/get-opentok-session-key/{uid}', 'ProController@getOpentokSessionKey');
 
     Route::get('/pro/logout', 'AppSessionController@processProLogOut')->name('pro-logout');