Browse Source

Use RecordRTC or Wami adding audio on execises tool - refs BT#11060

Angel Fernando Quiroz Campos 9 years ago
parent
commit
72cd91d40f

+ 32 - 33
main/exercice/exercise.class.php

@@ -3167,7 +3167,7 @@ class Exercise
         $totalScore = 0;
 
         // Destruction of the Question object
-        unset($objQuestionTmp);
+        //unset($objQuestionTmp);
 
         // Construction of the Answer object
         $objAnswerTmp = new Answer($questionId);
@@ -3185,34 +3185,20 @@ class Exercise
             $nbrAnswers = 1;
         }
 
-        $nano = null;
-        $wamiRecorder = null;
-
         if ($answerType == ORAL_EXPRESSION) {
             $exe_info = Event::get_exercise_results_by_attempt($exeId);
             $exe_info = isset($exe_info[$exeId]) ? $exe_info[$exeId] : null;
 
-            $params = array();
-            $params['course_id'] = $course_id;
-            $params['session_id'] = api_get_session_id();
-            $params['user_id'] = isset($exe_info['exe_user_id'])? $exe_info['exe_user_id'] : api_get_user_id();
-            $params['exercise_id'] = isset($exe_info['exe_exo_id'])? $exe_info['exe_exo_id'] : $this->id;
-            $params['question_id'] = $questionId;
-            $params['exe_id'] = isset($exe_info['exe_id']) ? $exe_info['exe_id'] : $exeId;
-
-            $nano = new Nanogong($params);
-            $wamiRecorder = new WamiRecorder(
-                api_get_course_int_id(),
+            $objQuestionTmp->initFile(
                 api_get_session_id(),
                 isset($exe_info['exe_user_id']) ? $exe_info['exe_user_id'] : api_get_user_id(),
                 isset($exe_info['exe_exo_id']) ? $exe_info['exe_exo_id'] : $this->id,
-                $questionId,
                 isset($exe_info['exe_id']) ? $exe_info['exe_id'] : $exeId
             );
 
             //probably this attempt came in an exercise all question by page
             if ($feedback_type == 0) {
-                $nano->replace_with_real_exe($exeId);
+                $objQuestionTmp->replaceWithRealExe($exeId);
             }
         }
 
@@ -3845,10 +3831,11 @@ class Exercise
                         $query  = "SELECT answer, marks FROM ".$TBL_TRACK_ATTEMPT."
                                    WHERE exe_id = '".$exeId."' AND question_id= '".$questionId."'";
                         $resq   = Database::query($query);
-                        $choice = Database::result($resq,0,'answer');
+                        $row = Database::fetch_assoc($resq);
+                        $choice = $row['answer'];
                         $choice = str_replace('\r\n', '', $choice);
                         $choice = stripslashes($choice);
-                        $questionScore = Database::result($resq,0,"marks");
+                        $questionScore = $row['marks'];
                         if ($questionScore==-1) {
                             $totalScore+=0;
                         } else {
@@ -4195,7 +4182,8 @@ class Exercise
                                 $choice,
                                 0,
                                 0,
-                                $wamiRecorder);
+                                $objQuestionTmp->getFileUrl()
+                            );
                             //}
                         } elseif ($answerType == HOT_SPOT) {
                             //if ($origin != 'learnpath') {
@@ -4527,7 +4515,7 @@ class Exercise
                                     $choice,
                                     $exeId,
                                     $questionId,
-                                    $wamiRecorder
+                                    $objQuestionTmp->getFileUrl()
                                 ) . '</td>
                                 </tr>
                                 </table>';
@@ -5043,7 +5031,16 @@ class Exercise
                 Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id);
             } elseif ($answerType == ORAL_EXPRESSION) {
                 $answer = $choice;
-                Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id, $nano);
+                Event::saveQuestionAttempt(
+                    $questionScore,
+                    $answer,
+                    $quesId,
+                    $exeId,
+                    0,
+                    $this->id,
+                    false,
+                    $objQuestionTmp->getAbsoluteFilePath()
+                );
             } elseif (in_array($answerType, [UNIQUE_ANSWER, UNIQUE_ANSWER_IMAGE, UNIQUE_ANSWER_NO_OPTION])) {
                 $answer = $choice;
                 Event::saveQuestionAttempt($questionScore, $answer, $quesId, $exeId, 0, $this->id);
@@ -6850,6 +6847,7 @@ class Exercise
 
             $nbrAnswers = $objAnswerTmp->selectNbrAnswers();
             $course_id = api_get_course_int_id();
+            $sessionId = api_get_session_id();
             $quiz_question_options = Question::readQuestionOption($questionId, $course_id);
 
             // For "matching" type here, we need something a little bit special
@@ -6914,27 +6912,28 @@ class Exercise
                 $s .= $form->return_form();
             } elseif ($answerType == ORAL_EXPRESSION) {
                 // Add nanogong
-                if (api_get_setting('document.enable_nanogong') == 'true') {
+                if (api_get_setting('enable_record_audio') === 'true') {
 
                     //@todo pass this as a parameter
                     global $exercise_stat_info, $exerciseId;
 
                     if (!empty($exercise_stat_info)) {
-                        $params = array(
-                            'exercise_id' => $exercise_stat_info['exe_exo_id'],
-                            'exe_id' => $exercise_stat_info['exe_id'],
-                            'question_id' => $questionId
+                        $objQuestionTmp->initFile(
+                            api_get_session_id(),
+                            api_get_user_id(),
+                            $exercise_stat_info['exe_exo_id'],
+                            $exercise_stat_info['exe_id']
                         );
                     } else {
-                        $params = array(
-                            'exercise_id' => $exerciseId,
-                            'exe_id' => 'temp_exe',
-                            'question_id' => $questionId
+                        $objQuestionTmp->initFile(
+                            api_get_session_id(),
+                            api_get_user_id(),
+                            $exerciseId,
+                            'temp_exe'
                         );
                     }
 
-                    $nano = new Nanogong($params);
-                    $s .= $nano->show_button();
+                    $s .= $objQuestionTmp->returnRecorder();
                 }
 
                 $form->addElement('html_editor', "choice[".$questionId."]", null, array('id' => "choice[".$questionId."]"), array('ToolbarSet' => 'TestFreeAnswer'));

+ 0 - 2
main/exercice/exercise_show.php

@@ -398,7 +398,6 @@ foreach ($questionList as $questionId) {
         $questionScore = $question_result['score'];
         $totalScore += $question_result['score'];
     } elseif ($answerType == FREE_ANSWER) {
-        $answer = $str;
         $question_result = $objExercise->manage_answer(
             $id,
             $questionId,
@@ -413,7 +412,6 @@ foreach ($questionList as $questionId) {
         $questionScore = $question_result['score'];
         $totalScore += $question_result['score'];
     } elseif ($answerType == ORAL_EXPRESSION) {
-        $answer = $str;
         $question_result = $objExercise->manage_answer(
             $id,
             $questionId,

+ 7 - 0
main/exercice/exercise_submit.php

@@ -63,6 +63,13 @@ $htmlHeadXtra[] = api_get_js('epiclock/renderers/minute/epiclock.minute.js');
 $htmlHeadXtra[] = '<link rel="stylesheet" href="' . api_get_path(WEB_LIBRARY_JS_PATH) . 'hotspot/css/hotspot.css">';
 $htmlHeadXtra[] = '<script src="' . api_get_path(WEB_LIBRARY_JS_PATH) . 'hotspot/js/hotspot.js"></script>';
 
+if (api_get_setting('enable_record_audio') === 'true') {
+    $htmlHeadXtra[] = '<script src="' . api_get_path(WEB_LIBRARY_JS_PATH) . 'rtc/RecordRTC.js"></script>';
+    $htmlHeadXtra[] = '<script src="' . api_get_path(WEB_LIBRARY_PATH) . 'wami-recorder/recorder.js"></script>';
+    $htmlHeadXtra[] = '<script src="' . api_get_path(WEB_LIBRARY_PATH) . 'wami-recorder/gui.js"></script>';
+    $htmlHeadXtra[] = '<script type="text/javascript" src="' . api_get_path(WEB_LIBRARY_PATH) . 'swfobject/swfobject.js"></script>';
+}
+
 $template = new Template();
 
 // General parameters passed via POST/GET

+ 209 - 0
main/exercice/oral_expression.class.php

@@ -14,6 +14,16 @@ class OralExpression extends Question
     static $typePicture = 'audio_question.png';
     static $explanationLangVar = 'OralExpression';
 
+    private $sessionId;
+    private $userId;
+    private $exerciseId;
+    private $exeId;
+    private $storePath;
+    private $fileName;
+    private $filePath;
+
+    public $available_extensions = array('wav', 'ogg');
+
     /**
      * Constructor
      */
@@ -76,4 +86,203 @@ class OralExpression extends Question
 
         return $header;
     }
+
+    /**
+     * initialize the attributes to generate the file path
+     * @param $sessionId integer
+     * @param $userId integer
+     * @param $exerciseId integer
+     * @param $exeId integer
+     */
+    public function initFile($sessionId, $userId, $exerciseId, $exeId)
+    {
+        $this->sessionId = intval($sessionId);
+        $this->userId = intval($userId);
+
+        $this->exerciseId = 0;
+
+        if (!empty($exerciseId)) {
+            $this->exerciseId = intval($exerciseId);
+        }
+
+        $this->exeId = intval($exeId);
+
+        $this->storePath = $this->generateDirectory();
+        $this->fileName = $this->generateFileName();
+        $this->filePath = $this->storePath . $this->fileName;
+    }
+
+    /**
+     * Generate the necessary directory for audios. If them not exists, are created
+     * @return string
+     */
+    private function generateDirectory()
+    {
+        $this->storePath = api_get_path(SYS_COURSE_PATH) . $this->course['path'] . '/exercises/';
+
+        if (!is_dir($this->storePath)) {
+            mkdir($this->storePath);
+        }
+
+        if (!is_dir($this->storePath . $this->sessionId)) {
+            mkdir($this->storePath . $this->sessionId);
+        }
+
+        if (!empty($this->exerciseId) && !is_dir($this->storePath . $this->sessionId . '/' . $this->exerciseId)) {
+            mkdir($this->storePath . $this->sessionId . '/' . $this->exerciseId);
+        }
+
+        if (!empty($this->id) && !is_dir($this->storePath . $this->sessionId . '/' . $this->exerciseId . '/' . $this->id)) {
+            mkdir($this->storePath . $this->sessionId . '/' . $this->exerciseId . '/' . $this->id);
+        }
+
+        if (!empty($this->userId) && !is_dir($this->storePath . $this->sessionId . '/' . $this->exerciseId . '/' . $this->id . '/' . $this->userId)) {
+            mkdir($this->storePath . $this->sessionId . '/' . $this->exerciseId . '/' . $this->id . '/' . $this->userId);
+        }
+
+        return $this->storePath .= implode(
+                '/',
+                array(
+                    $this->sessionId,
+                    $this->exerciseId,
+                    $this->id,
+                    $this->userId
+                )
+            ) . '/';
+    }
+
+    /**
+     * Generate the file name
+     * @return string
+     */
+    private function generateFileName()
+    {
+        return implode(
+            '-',
+            array(
+                $this->course['real_id'],
+                $this->sessionId,
+                $this->userId,
+                $this->exerciseId,
+                $this->id,
+                $this->exeId
+            )
+        );
+    }
+
+    /**
+     * Generate a relative directory path
+     * @return string
+     */
+    private function generateRelativeDirectory()
+    {
+        return '/exercises/' . implode(
+            '/',
+            [$this->sessionId, $this->exerciseId, $this->id, $this->userId]
+        ) . '/';
+    }
+
+    /**
+     * Return the HTML code to show the RecordRTC/Wami recorder
+     * @return string
+     */
+    public function returnRecorder()
+    {
+        $directory = '/..' . $this->generateRelativeDirectory();
+
+        $recordAudioView = new Template('', false, false,false, false, false, false);
+        $recordAudioView->assign('directory', $directory);
+        $recordAudioView->assign('user_id', $this->userId);
+        $recordAudioView->assign('file_name', $this->fileName);
+
+        $template = $recordAudioView->get_template('exercise/oral_expression.tpl');
+
+        return $recordAudioView->fetch($template);
+    }
+
+    /**
+     * Get the absolute file path. Return null if the file doesn't exists
+     * @param bool $loadFromDatabase
+     * @return string
+     */
+    public function getAbsoluteFilePath($loadFromDatabase = false)
+    {
+        $fileName = $this->fileName;
+
+        if ($loadFromDatabase) {
+            $em = Database::getManager();
+            //Load the real filename just if exists
+            if (isset($this->exeId, $this->userId, $this->id, $this->sessionId, $this->course['real_id'])) {
+                $result = $em
+                    ->getRepository('ChamiloCoreBundle:TrackEAttempt')
+                    ->findOneBy([
+                        'exeId' => $this->exeId,
+                        'userId' => $this->userId,
+                        'questionId' => $this->id,
+                        'sessionId' => $this->sessionId,
+                        'cId' => $this->course['real_id']
+                    ]);
+
+                if (!$result) {
+                    return null;
+                }
+
+                return $this->storePath . $result->getFilename();
+            }
+        }
+
+        foreach ($this->available_extensions as $extension) {
+            if (!is_file($this->storePath . $fileName . ".$extension.$extension")) {
+                continue;
+            }
+
+            return "{$this->storePath}$fileName.$extension.$extension";
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the URL for the audio file. Return null if the file doesn't exists
+     * @return string
+     */
+    public function getFileUrl()
+    {
+        $filePath = $this->getAbsoluteFilePath();
+
+        if (empty($filePath)) {
+            return null;
+        }
+
+        return str_replace(
+            api_get_path(SYS_COURSE_PATH),
+            api_get_path(WEB_COURSE_PATH),
+            $filePath
+        );
+    }
+
+    /**
+     * Tricky stuff to deal with the feedback = 0 in exercises (all question per page)
+     * @param $exe_id integer
+     */
+    public function replaceWithRealExe($exe_id)
+    {
+        $filename = null;
+        //ugly fix
+        foreach ($this->available_extensions as $extension) {
+            $items = explode('-', $this->fileName);
+            $items[5] = 'temp_exe';
+            $filename = implode('-', $items);
+
+            if (is_file($this->storePath . $filename . '.' . $extension)) {
+                $old_name = $this->storePath . $filename . '.' . $extension;
+                $items = explode('-', $this->fileName);
+                $items[5] = $exe_id;
+                $filename = $filename = implode('-', $items);
+                $new_name = $this->storePath . $filename . '.' . $extension;
+                rename($old_name, $new_name);
+                break;
+            }
+        }
+    }
 }

+ 2 - 2
main/exercice/question.class.php

@@ -1357,7 +1357,7 @@ abstract class Question
      */
     public static function get_question_type($type)
     {
-        if ($type == ORAL_EXPRESSION && api_get_setting('enable_nanogong') != 'true') {
+        if ($type == ORAL_EXPRESSION && api_get_setting('enable_record_audio') !== 'true') {
             return null;
         }
         return self::$questionTypes[$type];
@@ -1368,7 +1368,7 @@ abstract class Question
      */
     public static function get_question_type_list()
     {
-        if (api_get_setting('enable_nanogong') != 'true') {
+        if (api_get_setting('enable_record_audio') !== 'true') {
             self::$questionTypes[ORAL_EXPRESSION] = null;
             unset(self::$questionTypes[ORAL_EXPRESSION]);
         }

+ 0 - 98
main/inc/ajax/nanogong.ajax.php

@@ -1,98 +0,0 @@
-<?php
-/* For licensing terms, see /license.txt */
-
-/**
- * Responses to AJAX calls
- */
-require_once '../global.inc.php';
-
-//@todo for some reason nanogong doesn't like this variables
-
-$action = $_REQUEST['a'];
-unset($_REQUEST['a']);
-$js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
-
-//Fix in order to add the exe_id
-
-if (isset($_REQUEST['from_htaccess'])) {
-	if (isset($_REQUEST['file'])) {
-		$fileinfo = pathinfo($_REQUEST['file']);
-		$items = explode('-', $fileinfo['filename']);
-		$_REQUEST['exe_id'] = $items[5];
-	}
-}
-$nano = new Nanogong($_REQUEST);
-$is_nano = false;
-
-if (isset($_REQUEST['is_nano'])) {
-	$is_nano = true;
-}
-
-switch ($action) {
-	case 'get_file':
-		if ($nano->get_param_value('user_id') == api_get_user_id() || api_is_allowed_to_edit()) {
-			$file_path = $nano->load_filename_if_exists();
-			if ($file_path) {
-				$info = pathinfo($file_path);
-				$user_info = api_get_user_info($nano->params['user_id']);
-				$name = get_lang('Quiz').'-'.$user_info['firstname'].'-'.$user_info['lastname'].'.'.$info['extension'];
-				$download = true;
-				if (isset($_REQUEST['download']) && $_REQUEST['download'] == 0) {
-					$download = false;
-				}
-				DocumentManager::file_send_for_download($file_path, $download);
-				exit;
-			}
-		}
-		break;
-	case 'show_audio':
-		if (!$is_nano) {
-			echo $nano->return_js($_REQUEST);
-		}
-		echo $nano->show_audio_file($is_nano);
-		break;
-	case 'delete':
-		$return = $nano->delete_files();
-		if ($return == 1) {
-			//cant' do this because the post that nano send doesnt take into account the session
-			Display::display_confirmation_message(get_lang('FileDeleted'));
-		} else {
-			Display::display_confirmation_message(get_lang('FileNotFound'));
-		}
-		break;
-	case 'show_form':
-		api_protect_course_script(true);
-		Display::display_reduced_header();
-		echo $nano->return_js($_REQUEST);
-		echo $nano->return_form();
-		break;
-    case 'save_file':
-    	// User access same as upload.php
-    	$return = $nano->upload_file($is_nano);
-
-    	if ($is_nano) {
-    		//nano looks for numbers
-	    	if ($return == 1) {
-	    		//cant' do this because the post that nano send doesnt take into account the session
-	    		echo 1; //Display::display_confirmation_message(get_lang('UplUploadSucceeded'));
-	    	} else {
-	    		echo 0;
-	    		//Display::display_warning_message(get_lang('UplUnableToSaveFileFilteredExtension'));
-	    	}
-    	} else {
-    		Display::display_reduced_header();
-    		echo $nano->return_js($_REQUEST);
-    		//normal form
-    		if ($return == 1) {
-    			//cant' do this because the post that nano send doesnt take into account the session
-    			$message = Display::return_message(get_lang('UplUploadSucceeded'), 'confirm');
-    		} else {
-    			$message = Display::return_message(get_lang('UplUnableToSaveFileFilteredExtension'), 'warning');
-    		}
-    		echo $nano->return_form($message);
-    	}
-        break;
-    default:
-        echo '';
-}
-exit;

+ 0 - 28
main/inc/ajax/wamirecorder.ajax.php

@@ -1,28 +0,0 @@
-<?php
-/* For license terms, see /license.txt */
-/**
- * AJAX Call for wamirecorder
- */
-require_once '../global.inc.php';
-
-$action = $_REQUEST['a'];
-
-//$js_path = api_get_path(WEB_LIBRARY_PATH) . 'javascript/';
-
-$courseId = isset($_REQUEST['course_id']) ? $_REQUEST['course_id'] : 0;
-$sessionId = isset($_REQUEST['session_id']) ? $_REQUEST['session_id'] : 0;
-$userId = isset($_REQUEST['user_id']) ? $_REQUEST['user_id'] : 0;
-$exerciseId = isset($_REQUEST['exercise_id']) ? $_REQUEST['exercise_id'] : 0;
-$questionId = isset($_REQUEST['question_id']) ? $_REQUEST['question_id'] : 0;
-$exeId = isset($_REQUEST['exe_id']) ? $_REQUEST['exe_id'] : 0;
-
-$wamiRecorder = new WamiRecorder($courseId, $sessionId, $userId, $exerciseId, $questionId, $exeId);
-
-switch ($action) {
-    case 'show_form':
-                api_protect_course_script(true);
-        		Display::display_reduced_header();
-                $wamiRecorder->showJS();
-                $wamiRecorder->showForm();
-                break;
-}

+ 0 - 386
main/inc/lib/WamiRecorder.php

@@ -1,386 +0,0 @@
-<?php
-
-/* For license terms, see /license.txt */
-
-class WamiRecorder
-{
-    public $courseInfo;
-    public $userId;
-    public $exeId;
-    public $exerciseId;
-    public $questionId;
-    public $courseId;
-    public $sessionId;
-    public $storePath;
-    public $fileName;
-    public $filePath;
-    public $canEdit;
-
-    /**
-     * WamiRecorder constructor.
-     * @param int $courseId
-     * @param int $sessionId
-     * @param int $userId
-     * @param int $exerciseId
-     * @param int $questionId
-     * @param int $exeId
-     */
-    public function __construct($courseId = 0, $sessionId = 0, $userId = 0, $exerciseId = 0, $questionId = 0, $exeId = 0)
-    {
-        if (!empty($courseId)) {
-            $this->courseId = intval($courseId);
-        } else {
-            $this->courseId = api_get_course_int_id();
-        }
-
-        $this->courseInfo = api_get_course_info_by_id($this->courseId);
-
-        if (!empty($sessionId)) {
-            $this->sessionId = intval($sessionId);
-        } else {
-            $this->sessionId = api_get_session_id();
-        }
-
-        if (!empty($userId)) {
-            $this->userId = intval($userId);
-        } else {
-            $this->userId = api_get_user_id();
-        }
-
-        $this->exerciseId = 0;
-
-        if (!empty($exerciseId)) {
-            $this->exerciseId = intval($exerciseId);
-        }
-
-        $this->questionId = 0;
-
-        if (!empty($questionId)) {
-            $this->questionId = intval($questionId);
-        }
-
-        $this->canEdit = false;
-
-        if (api_is_allowed_to_edit()) {
-            $this->canEdit = true;
-        } else {
-            if ($this->userId == api_get_user_id()) {
-                $this->canEdit = true;
-            }
-        }
-
-        $this->exeId = intval($exeId);
-
-        $this->storePath = $this->generateDirectory();
-        $this->fileName = $this->generateFileName();
-        $this->filePath = $this->storePath . $this->fileName;
-    }
-
-    /**
-     * Generate the file name
-     * @return string
-     */
-    private function generateFileName()
-    {
-        return implode(
-            '-',
-            array(
-                $this->courseId,
-                $this->sessionId,
-                $this->userId,
-                $this->exerciseId,
-                $this->questionId,
-                $this->exeId
-            )
-        );
-    }
-
-    /**
-     * Generate the necessary directory for audios. If them not exists, are created
-     * @return string
-     */
-    private function generateDirectory()
-    {
-        $this->storePath = api_get_path(SYS_COURSE_PATH) . $this->courseInfo['path'] . '/exercises/';
-
-        if (!is_dir($this->storePath)) {
-            mkdir($this->storePath);
-        }
-
-        if (!is_dir($this->storePath . $this->sessionId)) {
-            mkdir($this->storePath . $this->sessionId);
-        }
-
-        if (!empty($this->exerciseId) && !is_dir($this->storePath . $this->sessionId . '/' . $this->exerciseId)) {
-            mkdir($this->storePath . $this->sessionId . '/' . $this->exerciseId);
-        }
-
-        if (!empty($this->questionId) && !is_dir($this->storePath . $this->sessionId . '/' . $this->exerciseId . '/' . $this->questionId)) {
-            mkdir($this->storePath . $this->sessionId . '/' . $this->exerciseId . '/' . $this->questionId);
-        }
-
-        if (!empty($this->userId) && !is_dir($this->storePath . $this->sessionId . '/' . $this->exerciseId . '/' . $this->questionId . '/' . $this->userId)) {
-            mkdir($this->storePath . $this->sessionId . '/' . $this->exerciseId . '/' . $this->questionId . '/' . $this->userId);
-        }
-
-        return $this->storePath .= implode(
-                '/',
-                array(
-                    $this->sessionId,
-                    $this->exerciseId,
-                    $this->questionId,
-                    $this->userId
-                )
-            ) . '/';
-    }
-
-    /**
-     * Generate a relative directory path
-     * @return string
-     */
-    private function generateRelativeDirectory()
-    {
-        return implode(
-            '/',
-            array(
-                $this->sessionId,
-                $this->exerciseId,
-                $this->questionId,
-                $this->userId
-            )
-        );
-    }
-
-    /**
-     * Get necessary params for Flash
-     * @return string
-     */
-    private function getParams()
-    {
-        return http_build_query(array(
-            'course_id' => $this->courseId,
-            'session_id' => $this->sessionId,
-            'exercise_id' => $this->exerciseId,
-            'exe_id' => $this->exeId,
-            'question_id' => $this->questionId,
-            'user_id' => $this->userId
-        ));
-    }
-
-    /**
-     * Print the JavaScript for Wami
-     */
-    public function showJS()
-    {
-        $wamidir = '/../exercises/' . $this->generateRelativeDirectory() . '/';
-        $wamiurlplay = api_get_path(WEB_COURSE_PATH) . api_get_course_path($this->courseInfo['code']) . '/exercises/' . $this->generateRelativeDirectory();
-        $wamiuserid = $this->userId;
-
-        echo '
-            <!-- swfobject is a commonly used library to embed Flash content https://ajax.googleapis.com/ajax/libs/swfobject/2.2/ -->
-            <script type="text/javascript" src="' . api_get_path(WEB_LIBRARY_PATH) . 'swfobject/swfobject.js"></script>
-
-            <!-- Setup the recorder interface -->
-            <script type="text/javascript" src="' . api_get_path(WEB_LIBRARY_PATH) . 'wami-recorder/recorder.js"></script>
-
-            <!-- GUI code... take it or leave it -->
-            <script type="text/javascript" src="' . api_get_path(WEB_LIBRARY_PATH) . 'wami-recorder/gui.js"></script>
-
-            <script type="text/javascript">
-
-                function newNameRecord() {
-                    location.reload(true)
-                }
-
-                function setupRecorder() {
-                    document.getElementById(\'audio_button\').style.display = \'none\';
-
-                    Wami.setup({
-                        id : \'wami\',
-                        onReady : setupGUI
-                    });
-                }
-
-                function setupGUI() {
-                    var waminame = \'' . $this->fileName . '.wav\';
-                    var waminame_play=waminame;
-
-                    var gui = new Wami.GUI({
-                        id : \'wami\',
-                        singleButton : true,
-                        recordUrl: \'' . api_get_path(WEB_AJAX_PATH) . 'record_audio_wami.ajax.php?waminame=\' + waminame + \'&wamidir=' . $wamidir . '&wamiuserid=' . $wamiuserid . '\',
-                        playUrl: \'' . $wamiurlplay . '\' + waminame_play,
-                        buttonUrl: \'' . api_get_path(WEB_LIBRARY_PATH) . 'wami-recorder/buttons.png\',
-                        swfUrl: \'' . api_get_path(WEB_LIBRARY_PATH) . 'wami-recorder/Wami.swf\'
-                    });
-
-                    gui.setPlayEnabled(false);
-                }
-
-            </script>
-        ';
-    }
-
-    /**
-     * Show the form controls to Wami
-     */
-    public function showForm()
-    {
-        echo '
-            <div id="wami" style="padding-top:10px;"></div>
-            <div align="center" style="padding-top:150px;">
-                <form name="form_wami_recorder">
-                    <button type="button" value="" onclick="setupRecorder()" id="audio_button" />' . get_lang('Activate') . '</button>
-                    <button type="button" value="" onclick="newNameRecord()" id="new_name" />' . get_lang('Reload') . '</button>
-                </form>
-            </div>
-        ';
-    }
-
-    /**
-     * Get a HTML button for record answer
-     * @return string
-     */
-    public function getButton()
-    {
-        $params_strings = $this->getParams();
-        $params_strings .= '&a=show_form';
-
-        $html = "
-            <script>
-                $(document).on('ready', function () {
-                    $('#btn-record_answer').on('click', function (e) {
-                        e.preventDefault();
-
-                        var url = '" . api_get_path(WEB_AJAX_PATH) . "wamirecorder.ajax.php?" . $params_strings . "',
-                            iframe = $('<iframe>').attr({
-                                hspace: 0,
-                                src: url,
-                                frameborder: 0,
-                                width: '100%',
-                                height: 400
-                            });
-
-                        var modalDialog = $('#global-modal').find('.modal-dialog'),
-                                modalTitle = '" . get_lang('RecordAnswer') ."';
-
-                        modalDialog
-                            .removeClass('modal-lg modal-sm')
-                            .css('width', '500px')
-
-                        $('#global-modal').find('.modal-title').text(modalTitle);
-                        $('#global-modal').find('.modal-body').html(iframe);
-                        $('#global-modal').modal('show');
-                    });
-                });
-            </script>
-        ";
-        $html .= '<br />'
-            . Display::toolbarButton(
-                get_lang('RecordAnswer'),
-                api_get_path(WEB_AJAX_PATH) . 'wamirecorder.ajax.php?' . $params_strings . http_build_query([
-                    'a' => 'show_form',
-                    'TB_iframe' => 'true',
-                    'data-height' => 400,
-                    'data-width' => 500
-                ]),
-                'microphone',
-                'primary',
-                ['id' => 'btn-record_answer']
-            )
-            . '<br /><br />' . Display::return_message(get_lang('UseTheMessageBelowToAddSomeComments'));
-        return $html;
-    }
-
-    /**
-     * Show the audio file
-     * @return null|string
-     */
-    public function showAudioFile()
-    {
-        $filePath = $this->loadFileIfExists();
-
-        if (empty($filePath)) {
-            return null;
-        }
-
-        $url = $this->getPublicURL();
-
-        $params = array(
-            'url' => $url,
-            'extension' => 'wav',
-            'count' => 1
-        );
-
-        $jquery = DocumentManager::generate_jplayer_jquery($params);
-
-        $jsPath = api_get_path(WEB_LIBRARY_PATH) . 'javascript/';
-        $actions = Display::url(Display::return_icon('save.png', get_lang('Download'), array(), ICON_SIZE_SMALL), $url, array('target' => '_blank'));
-
-        $html = '<link rel="stylesheet" href="' . $jsPath . 'jquery-jplayer/skins/blue/jplayer.blue.monday.css" type="text/css">';
-        //$html .= '<link rel="stylesheet" href="' . $jsPath . 'jquery-jplayer/skins/chamilo/jplayer.blue.monday.css" type="text/css">';
-        $html .= '<script type="text/javascript" src="' . $jsPath . 'jquery-jplayer/jquery.jplayer.min.js"></script>';
-
-        $html .= '<div class="nanogong_player"></div>';
-        $html .= '<br /><div class="action_player">' . $actions . '</div><br /><br /><br />';
-        $html .= '<script>
-            $(document).ready( function() {        
-                //Experimental changes to preview mp3, ogg files        
-                 ' . $jquery . '                 
-            });
-            </script>';
-        $html .= DocumentManager::generate_media_preview(1, 'advanced');
-
-        return $html;
-    }
-
-    /**
-     * Get the audio file
-     * @param bool $loadFromDatabase
-     * @return null|string
-     */
-    public function loadFileIfExists($loadFromDatabase = false)
-    {
-        $fileName = $this->fileName . '.wav';
-
-        //temp_exe
-        if ($loadFromDatabase) {
-            //Load the real filename just if exists
-            if (isset($this->exeId) && isset($this->userId) && isset($this->questionId) && isset($this->sessionId) && isset($this->courseId)) {
-                $attempt_table = Database::get_statistic_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
-
-                $sql = "SELECT filename FROM $attempt_table
-                        WHERE exe_id = " . $this->exeId . " AND
-                                user_id = " . $this->userId . " AND
-                                question_id = " . $this->questionId . " AND
-                                session_id = " . $this->sessionId . " AND
-                                course_code = '" . $this->courseInfo['code'] . "' LIMIT 1";
-                $result = Database::query($sql);
-                $result = Database::fetch_row($result, 'ASSOC');
-
-                if (isset($result) && isset($result[0]) && !empty($result[0])) {
-                    $fileName = $result[0];
-                }
-            }
-        }
-
-        if (is_file($this->storePath . $fileName)) {
-            return $this->storePath . $fileName;
-        }
-
-        return null;
-    }
-
-    /**
-     * Get a public URL
-     * @return string
-     */
-    public function getPublicURL()
-    {
-        $url = api_get_path(WEB_COURSE_PATH) . $this->courseInfo['path'] . '/exercises/';
-        $url .= $this->generateRelativeDirectory() . '/';
-        $url .= $this->fileName . '.wav';
-
-        return $url;
-    }
-}

+ 7 - 27
main/inc/lib/document.lib.php

@@ -5318,7 +5318,7 @@ class DocumentManager
             if ($filetype == 'file') {
                 // Sound preview with jplayer
                 if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
-                    (preg_match('/wav$/i', urldecode($checkExtension)) && !preg_match('/_chnano_.wav$/i', urldecode($url))) ||
+                    (preg_match('/wav$/i', urldecode($checkExtension))) ||
                     preg_match('/ogg$/i', urldecode($checkExtension))
                 ) {
                     return '<span style="float:left" ' . $visibility_class . '>' .
@@ -5333,12 +5333,7 @@ class DocumentManager
                     preg_match('/jpg$/i', urldecode($checkExtension)) ||
                     preg_match('/jpeg$/i', urldecode($checkExtension)) ||
                     preg_match('/bmp$/i', urldecode($checkExtension)) ||
-                    preg_match('/svg$/i', urldecode($checkExtension)) ||
-                    (
-                        preg_match('/wav$/i', urldecode($checkExtension)) &&
-                        preg_match('/_chnano_.wav$/i', urldecode($checkExtension)) &&
-                        api_get_setting('enable_nanogong') == 'true'
-                    )
+                    preg_match('/svg$/i', urldecode($checkExtension))
                 ) {
                     // Simpler version of showinframesmin.php with no headers
                     $url = 'show_content.php?' . api_get_cidreq() . '&id=' . $document_data['id'];
@@ -5388,7 +5383,7 @@ class DocumentManager
                 if ($filetype == 'file') {
                     //Sound preview with jplayer
                     if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
-                        (preg_match('/wav$/i', urldecode($checkExtension)) && !preg_match('/_chnano_.wav$/i', urldecode($url))) ||
+                        (preg_match('/wav$/i', urldecode($checkExtension))) ||
                         preg_match('/ogg$/i', urldecode($checkExtension))) {
                         $sound_preview = DocumentManager::generate_media_preview($counter);
 
@@ -5401,12 +5396,7 @@ class DocumentManager
                         preg_match('/jpg$/i', urldecode($checkExtension)) ||
                         preg_match('/jpeg$/i', urldecode($checkExtension)) ||
                         preg_match('/bmp$/i', urldecode($checkExtension)) ||
-                        preg_match('/svg$/i', urldecode($checkExtension)) ||
-                        (
-                            preg_match('/wav$/i', urldecode($checkExtension)) &&
-                            preg_match('/_chnano_.wav$/i', urldecode($checkExtension)) &&
-                            api_get_setting('enable_nanogong') == 'true'
-                        )
+                        preg_match('/svg$/i', urldecode($checkExtension))
                     ) {
                         $url = 'showinframes.php?' . api_get_cidreq() . '&id=' . $document_data['id'];
                         return '<a href="' . $url . '" title="' . $tooltip_title_alt . '" ' . $visibility_class . ' style="float:left">' .
@@ -5426,7 +5416,7 @@ class DocumentManager
                 if ($filetype == 'file') {
                     // Sound preview with jplayer
                     if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
-                        (preg_match('/wav$/i', urldecode($checkExtension)) && !preg_match('/_chnano_.wav$/i', urldecode($url))) ||
+                        (preg_match('/wav$/i', urldecode($checkExtension))) ||
                         preg_match('/ogg$/i', urldecode($checkExtension))) {
                         $sound_preview = DocumentManager::generate_media_preview($counter);
 
@@ -5441,12 +5431,7 @@ class DocumentManager
                         preg_match('/jpg$/i', urldecode($checkExtension)) ||
                         preg_match('/jpeg$/i', urldecode($checkExtension)) ||
                         preg_match('/bmp$/i', urldecode($checkExtension)) ||
-                        preg_match('/svg$/i', urldecode($checkExtension)) ||
-                        (
-                            preg_match('/wav$/i', urldecode($checkExtension)) &&
-                            preg_match('/_chnano_.wav$/i', urldecode($checkExtension)) &&
-                            api_get_setting('enable_nanogong') == 'true'
-                        )
+                        preg_match('/svg$/i', urldecode($checkExtension))
                     ) {
                         $url = 'showinframes.php?' . api_get_cidreq() . '&id=' . $document_data['id']; //without preview
                         return '<a href="' . $url . '" title="' . $tooltip_title_alt . '" ' . $visibility_class . ' style="float:left">' .
@@ -5479,12 +5464,7 @@ class DocumentManager
         if ($type == 'file') {
             $icon = choose_image($basename);
 
-            if (preg_match('/_chnano_.wav$/i', $basename)) {
-                $icon = "jplayer_play.png";
-                $basename = 'wav' . ' ' . '(Nanogong)';
-            } else {
-                $basename = substr(strrchr($basename, '.'), 1);
-            }
+            $basename = substr(strrchr($basename, '.'), 1);
         } else {
             if ($path == '/shared_folder') {
                 $icon = 'folder_users.gif';

+ 3 - 8
main/inc/lib/events.lib.php

@@ -406,7 +406,7 @@ class Event
      * @param	integer	Position
      * @param	integer Exercise ID (from c_quiz)
      * @param	bool update results?
-     * @param	string  Filename (for audio answers - using nanogong)
+     * @param	$fileName string  Filename (for audio answers - using nanogong)
      * @param	integer User ID The user who's going to get this score. Default value of null means "get from context".
      * @param	integer	Course ID (from the "id" column of course table). Default value of null means "get from context".
      * @param	integer	Session ID (from the session table). Default value of null means "get from context".
@@ -422,7 +422,7 @@ class Event
         $position,
         $exercise_id = 0,
         $updateResults = false,
-        $nano = null,
+        $fileName = null,
         $user_id = null,
         $course_id = null,
         $session_id = null,
@@ -479,11 +479,6 @@ class Event
             $answer = 0;
         }
 
-        $file = '';
-        if (isset($nano)) {
-            $file = Database::escape_string(basename($nano->load_filename_if_exists(false)));
-        }
-
         $session_id = api_get_session_id();
 
         if (!empty($question_id) && !empty($exe_id) && !empty($user_id)) {
@@ -496,7 +491,7 @@ class Event
                 'session_id' => $session_id,
                 'position' => $position,
                 'tms' => $now,
-                'filename' => $file,
+                'filename' => !empty($fileName) ? basename($fileName) : $fileName,
             );
 
             // Check if attempt exists.

+ 8 - 12
main/inc/lib/exercise.lib.php

@@ -166,31 +166,27 @@ class ExerciseLib
                 $s .= $form->returnForm();
             } elseif ($answerType == ORAL_EXPRESSION) {
                 // Add nanog
-                if (api_get_setting('enable_nanogong') == 'true') {
+                if (api_get_setting('enable_record_audio') == 'true') {
                     //@todo pass this as a parameter
                     global $exercise_stat_info, $exerciseId, $exe_id;
 
                     if (!empty($exercise_stat_info)) {
-                        $wamiRecorder = new WamiRecorder(
-                            0,
-                            0,
-                            0,
+                        $objQuestionTmp->initFile(
+                            api_get_session_id(),
+                            api_get_user_id(),
                             $exercise_stat_info['exe_exo_id'],
-                            $questionId,
                             $exercise_stat_info['exe_id']
                         );
                     } else {
-                        $wamiRecorder = new WamiRecorder(
-                            0,
-                            0,
-                            0,
+                        $objQuestionTmp->initFile(
+                            api_get_session_id(),
+                            api_get_user_id(),
                             $exerciseId,
-                            $questionId,
                             'temp_exe'
                         );
                     }
 
-                    echo $wamiRecorder->getButton();
+                    echo $objQuestionTmp->returnRecorder();
                 }
 
                 $form = new FormValidator('free_choice_'.$questionId);

+ 7 - 3
main/inc/lib/exercise_show_functions.lib.php

@@ -117,10 +117,14 @@ class ExerciseShowFunctions
         }
 	}
 
-	public static function display_oral_expression_answer($feedback_type, $answer, $id, $questionId, $nano = null)
+	public static function display_oral_expression_answer($feedback_type, $answer, $id, $questionId, $fileUrl = null)
     {
-        if (isset($nano)) {
-            echo $nano->showAudioFile();
+        if (isset($fileUrl)) {
+            echo '
+                <tr>
+                    <td><audio src="' . $fileUrl . '" controls></audio></td>
+                </tr>
+            ';
         }
 
         if (empty($id)) {

+ 0 - 670
main/inc/lib/nanogong.lib.php

@@ -1,670 +0,0 @@
-<?php
-/* For licensing terms, see /license.txt */
-
-/**
- * Class Nanogong
- *
- * Files are saved in the path:
- *  courses/XXX/exercises/(session_id)/(exercise_id)/(question_id)/(user_id)/
- *
- * The file name is composed with:
- * (course_id)/(session_id)/(user_id)/(exercise_id)/(question_id)/(exe_id).wav|mp3|ogg
- *
- *
- */
-class Nanogong
-{
-    public $filename;
-    public $store_filename;
-    public $store_path;
-    public $params;
-    public $can_edit = false;
-    public $course_id;
-    public $session_id;
-    public $exercise_id;
-    public $question_id;
-    public $user_id;
-    public $course_info;
-
-    /* Files allowed to upload */
-    public $available_extensions = array('mp3', 'wav', 'ogg');
-
-    /**
-     * @param array $params
-     */
-    public function __construct($params = array())
-    {
-        $this->set_parameters($params);
-    }
-
-    /**
-     * @return bool
-     */
-    public function create_user_folder()
-    {
-        //COURSE123/exercises/session_id/exercise_id/question_id/user_id
-        if (empty($this->store_path)) {
-            return false;
-        }
-
-        // Trying to create the courses/COURSE123/exercises/ dir just in case.
-        $directoryPermissions = api_get_permissions_for_new_directories();
-
-        if (!is_dir($this->store_path)) {
-            mkdir($this->store_path, $directoryPermissions);
-        }
-
-        if (!is_dir($this->store_path.$this->session_id)) {
-            mkdir($this->store_path.$this->session_id, $directoryPermissions);
-        }
-        if (!is_dir($this->store_path.$this->session_id.'/'.$this->exercise_id)) {
-            mkdir($this->store_path.$this->session_id.'/'.$this->exercise_id, $directoryPermissions);
-        }
-
-        if (!is_dir($this->store_path.$this->session_id.'/'.$this->exercise_id.'/'.$this->question_id)
-        ) {
-            mkdir($this->store_path.$this->session_id.'/'.$this->exercise_id.'/'.$this->question_id, $directoryPermissions);
-        }
-
-        if (!empty($this->user_id) &&
-            !is_dir($this->store_path.$this->session_id.'/'.$this->exercise_id.'/'.$this->question_id.'/'.$this->user_id)
-        ) {
-            mkdir($this->store_path.$this->session_id.'/'.$this->exercise_id.'/'.$this->question_id.'/'.$this->user_id, $directoryPermissions);
-        }
-	}
-
-    /**
-     * Setting parameters: course id, session id, etc
-     * @param    array
-     */
-    public function set_parameters($params = array())
-    {
-        // Setting course id
-        if (isset($params['course_id'])) {
-            $this->course_id = intval($params['course_id']);
-        } else {
-            $this->course_id = $params['course_id'] = api_get_course_int_id();
-        }
-
-        //Setting course info
-        if (isset($this->course_id)) {
-            $this->course_info = api_get_course_info_by_id($this->course_id);
-        }
-
-        //Setting session id
-        if (isset($params['session_id'])) {
-            $this->session_id = intval($params['session_id']);
-        } else {
-            $this->session_id = $params['session_id'] = api_get_session_id();
-        }
-
-        //Setting user ids
-        if (isset($params['user_id'])) {
-            $this->user_id = intval($params['user_id']);
-        } else {
-            $this->user_id = $params['user_id'] = api_get_user_id();
-        }
-
-        //Setting user ids
-        if (isset($params['exercise_id'])) {
-            $this->exercise_id = intval($params['exercise_id']);
-        } else {
-            $this->exercise_id = 0;
-        }
-
-        //Setting user ids
-        if (isset($params['question_id'])) {
-            $this->question_id = intval($params['question_id']);
-        } else {
-            $this->question_id = 0;
-        }
-
-		$this->can_edit = false;
-
-		if (api_is_allowed_to_edit()) {
-			$this->can_edit = true;
-		} else {
-			if ($this->user_id ==  api_get_user_id()) {
-				$this->can_edit = true;
-			}
-		}
-
-		// Settings the params array
-		$this->params = $params;
-		$this->store_path = api_get_path(SYS_COURSE_PATH).$this->course_info['path'].'/exercises/';
-		$this->create_user_folder();
-		$this->store_path = $this->store_path.implode('/', array($this->session_id, $this->exercise_id, $this->question_id, $this->user_id)).'/';
-		$this->filename = $this->generate_filename();
-		$this->store_filename = $this->store_path.$this->filename;
-	}
-
-    /**
-     * Generates the filename with the next format:
-     * (course_id)/(session_id)/(user_id)/(exercise_id)/(question_id)/(exe_id)
-     *
-     * @return string
-     */
-    public function generate_filename()
-    {
-        if (!empty($this->params)) {
-            //filename
-            //course_id/session_id/user_id/exercise_id/question_id/exe_id
-            $filename_array = array(
-                $this->params['course_id'],
-                $this->params['session_id'],
-                $this->params['user_id'],
-                $this->params['exercise_id'],
-                $this->params['question_id'],
-                $this->params['exe_id']
-            );
-
-            return implode('-', $filename_array);
-        } else {
-            return api_get_unique_id();
-        }
-    }
-
-    /**
-     * Delete audio file
-     * @return int
-     */
-    public function delete_files()
-    {
-        $delete_found = 0;
-        if ($this->can_edit) {
-            $file = $this->load_filename_if_exists();
-
-            $path_info = pathinfo($file);
-            foreach ($this->available_extensions as $extension) {
-                $file_to_delete = $path_info['dirname'].'/'.$path_info['filename'].'.'.$extension;
-                if (is_file($file_to_delete)) {
-                    unlink($file_to_delete);
-                    $delete_found = 1;
-                }
-            }
-        }
-
-        return $delete_found;
-    }
-
-	/**
-	 *
-	 * Tricky stuff to deal with the feedback = 0 in exercises (all question per page)
-     * @param int $exe_id
-	 */
-    public function replace_with_real_exe($exe_id)
-    {
-		$filename = null;
-		//@ugly fix
-		foreach($this->available_extensions as $extension) {
-			$items = explode('-', $this->filename);
-			$items[5] = 'temp_exe';
-			$filename = implode('-', $items);
-			if (is_file($this->store_path.$filename.'.'.$extension)) {
-				$old_name = $this->store_path.$filename.'.'.$extension;
-				$items = explode('-', $this->filename);
-				$items[5] = $exe_id;
-				$filename = $filename = implode('-', $items);
-				$new_name = $this->store_path.$filename.'.'.$extension;
-				rename($old_name, $new_name);
-				break;
-			}
-		}
-	}
-
-    /**
-     * @param bool $load_from_database
-     * @return null|string
-     */
-    public function load_filename_if_exists($load_from_database = false)
-    {
-		$filename = null;
-		//@ugly fix
-		foreach($this->available_extensions as $extension) {
-			if (is_file($this->store_path.$this->filename.'.'.$extension)) {
-				$filename = $this->filename.'.'.$extension;
-				break;
-			}
-		}
-
-		// temp_exe
-		if ($load_from_database) {
-
-			//Load the real filename just if exists
-			if (isset($this->params['exe_id']) && isset($this->params['user_id']) &&
-                isset($this->params['question_id']) && isset($this->params['session_id']) && isset($this->params['course_id'])
-            ) {
-				$attempt_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
-				$sql = "SELECT filename FROM $attempt_table
-                        WHERE
-                            exe_id = ".$this->params['exe_id']." AND
-                            user_id = ".$this->params['user_id']." AND
-                            question_id = ".$this->params['question_id']." AND
-                            session_id 	= ".$this->params['session_id']." AND
-                            course_code = '".$this->course_info['code']."'
-                        LIMIT 1";
-				$result = Database::query($sql);
-				$result = Database::fetch_row($result,'ASSOC');
-
-				if (isset($result) && isset($result[0]) && !empty($result[0])) {
-					$filename = $result[0];
-				}
-			}
-		}
-
-		if (is_file($this->store_path.$filename)) {
-			return $this->store_path.$filename;
-		}
-
-		return null;
-	}
-
-	/**
-	 *
-	 * Get the URL of the file
-	 * path courses/XXX/exercises/(session_id)/(exercise_id)/(question_id)/(user_id)/
-     * @param int $force_download
-	 *
-	 * @return string
-	 */
-    public function get_public_url($force_download = 0)
-    {
-		$params = $this->get_params();
-		$filename = basename($this->load_filename_if_exists());
-        $url = api_get_path(WEB_COURSE_PATH).$this->course_info['path'].'/exercises/'.$params['session_id'].'/'.$params['exercise_id'].'/'.$params['question_id'].'/'.$params['user_id'].'/'.$filename;
-		return $url;
-	}
-
-	/**
-	 * Uploads the nanogong wav file
-     * @param bool
-	 */
-	public function upload_file($is_nano = false)
-	{
-		if (!empty($_FILES)) {
-			$upload_ok = process_uploaded_file($_FILES['file'], false);
-
-			if (!is_uploaded_file($_FILES['file']['tmp_name'])) {
-				return 0;
-			}
-
-			if ($upload_ok) {
-				// Check if there is enough space to save the file
-				if (!DocumentManager::enough_space($_FILES['file']['size'], DocumentManager::get_course_quota())) {
-					return 0;
-				}
-
-				//first we delete everything before uploading the file
-				$this->delete_files();
-
-				//Reload the filename variable
-				$file_name = add_ext_on_mime($_FILES['file']['name'], $_FILES['file']['type']);
-				$file_name = strtolower($file_name);
-				$file_info = pathinfo($file_name);
-
-				if ($is_nano == true) {
-					$file_info['extension'] = 'wav';
-				}
-
-				$file_name = $this->filename.'.'.$file_info['extension'];
-
-				if (in_array($file_info['extension'], $this->available_extensions)) {
-					if (move_uploaded_file($_FILES['file']['tmp_name'], $this->store_path.$file_name)) {
-						$this->store_filename = $this->store_path.$file_name;
-						return 1;
-					}
-				}
-			}
-		}
-
-		return 0;
-	}
-
-	/**
-	 * Show the audio file + a button to download
-     * @param bool
-	 */
-	public function show_audio_file($show_delete_button = false)
-	{
-		$html = '';
-		$file_path = $this->load_filename_if_exists();
-
-		if (!empty($file_path)) {
-			$url = $this->get_public_url(true);
-			$actions = Display::url(Display::return_icon('save.png', get_lang('Download'), array(), ICON_SIZE_SMALL), $url, array('target'=>'_blank'));
-			$download_button = Display::url(get_lang('Download'), $url, array('class' =>'btn btn-default'));
-
-			if ($show_delete_button) {
-				$actions .= ' '.Display::url(Display::return_icon('delete.png', get_lang('Delete'), array(), ICON_SIZE_SMALL), "#", array('onclick'=>'delete_file();'));
-			}
-
-			$basename = basename($file_path);
-			$path_info = pathinfo($basename);
-
-			if ($path_info['extension'] == 'wav') {
-
-				$html .= '<script>
-				$(document).ready( function() {
-					var java_enabled = navigator.javaEnabled();
-
-					if (java_enabled) {
-						$("#nanogong_warning").hide();
-						$("#nanogong_player_id").show();
-					} else {
-						$("#nanogong_warning").show();
-						$("#nanogong_player_id").hide();
-					}
-				});
-				</script>';
-
-				$html .= '<div id="nanogong_player_id" class="nanogong_player_container">';
-					$html .= '<div class="action_player">'.$actions.'</div>';
-					$html .= '<div class="nanogong_player">';
-						$html .= '<applet id="nanogong_player" archive="'.api_get_path(WEB_LIBRARY_PATH).'nanogong/nanogong.jar" code="gong.NanoGong" width="250" height="95" ALIGN="middle">';
-						$html .= '<param name="ShowRecordButton" value="false" />'; // default true
-						$html .= '<param name="ShowSaveButton" value="false" />'; //you can save in local computer | (default true)
-						//echo '<param name="ShowAudioLevel" value="false" />'; //  it displays the audiometer | (default true)
-						$html .= '<param name="ShowTime" value="true" />'; // default false
-						$html .= '<param name="Color" value="#FFFFFF" />';
-                        $html .= '<param name="ShowSpeedButton" value="false" />';
-						//echo '<param name="StartTime" value="10.5" />';
-						//echo '<param name="EndTime" value="65" />';
-						$html .= '<param name="AudioFormat" value="ImaADPCM" />';// ImaADPCM (more speed), Speex (more compression)|(default Speex)
-						//$html .= '<param name="AudioFormat" value="Speex" />';// ImaADPCM (more speed), Speex (more compression)|(default Speex)
-						//Quality for ImaADPCM (low 8000, medium 11025, normal 22050, hight 44100) OR Quality for Speex (low 8000, medium 16000, normal 32000, hight 44100) | (default 44100)
-						//echo '<param name="SamplingRate" value="32000" />';
-						//echo '<param name="MaxDuration" value="60" />';
-						$html .=  '<param name="SoundFileURL" value="'.$url.'" />';//load a file |(default "")
-						$html .= '</applet>';
-					$html .= '</div>';
-				$html .= '</div>';
-                $html .= '<div id="nanogong_warning">'.Display::return_message(get_lang('BrowserDoesNotSupportNanogongPlayer'), 'warning').$download_button.'</div>';
-
-			} elseif(in_array($path_info['extension'],array('mp3', 'ogg','wav'))) {
-				$js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
-				$html .= '<link rel="stylesheet" href="'.$js_path.'jquery-jplayer/skin/blue.monday/css/jplayer.blue.monday.css" type="text/css">';
-				$html .= '<script type="text/javascript" src="'.$js_path.'jquery-jplayer/jplayer/jquery.jplayer.min.js"></script>';
-
-				$html .= '<div class="nanogong_player"></div>';
-				$html .= '<br /><div class="action_player">'.$actions.'</div><br /><br /><br />';
-
-                $params = array(
-                    'url' => $url,
-                    'extension' =>$path_info['extension'],
-                    'count'=> 1
-                 );
-                $jquery = DocumentManager::generate_jplayer_jquery($params);
-				$html .= '<script>
-				$(document).ready( function() {
-				    //Experimental changes to preview mp3, ogg files
-				     '.$jquery.'
-				});
-				</script>';
-				$html .= DocumentManager::generate_media_preview(1, 'advanced');
-			}
-		}
-        return $html;
-	}
-
-	/*
-	var filename = document.getElementById("audio_title").value+".wav";
-	var filename = filename.replace(/\s/g, "_");//replace spaces by _
-	var filename = encodeURIComponent(filename);
-	var filepath="'.urlencode($filepath).'";
-	var dir="'.urlencode($dir).'";
-	var course_code="'.urlencode($course_code).'";
-	var urlnanogong="'.$url.'?filename="+filename+"&filepath="+filepath+"&dir="+dir+"&course_code="+course_code;
-	*/
-
-	/**
-	 * Returns the nanogong javascript code
-	 * @return string
-	 */
-    public function return_js()
-    {
-		$params = $this->get_params(true);
-		$url = api_get_path(WEB_AJAX_PATH).'nanogong.ajax.php?a=save_file&'.$params.'&is_nano=1';
-		$url_load_file = api_get_path(WEB_AJAX_PATH).'nanogong.ajax.php?a=show_audio&'.$params;
-
-		$url_delete = api_get_path(WEB_AJAX_PATH).'nanogong.ajax.php?a=delete&'.$params;
-
-		$js =  '<script language="javascript">
-
-			//lang vars
-
-			var lang_no_applet				= "'.get_lang('NanogongNoApplet').'";
-			var lang_record_before_save		= "'.get_lang('NanogongRecordBeforeSave').'";
-			var lang_give_a_title			= "'.get_lang('NanogongGiveTitle').'";
-			var lang_failed_to_submit		= "'.get_lang('NanogongFailledToSubmit').'";
-			var lang_submitted				= "'.get_lang('NanogongSubmitted').'";
-			var lang_deleted				= "'.get_lang('Deleted').'";
-
-			var is_nano = 0;
-
-			function check_gong() {
-				//var record = document.getElementById("nanogong");
-				var recorder;
-				var java_enabled = navigator.javaEnabled()
-				return java_enabled;
-			}
-
-            function show_simple_upload_form() {
-                $("#no_nanogong_div").show();
-                //$("#nanogong_div").hide();
-                $("#preview").hide();
-            }
-
-			$(document).ready( function() {
-				$("#no_nanogong_div").hide();
-				$("#nanogong_div").hide();
-
-				var check_js = check_gong();
-
-				if (check_js == true) {
-					$("#nanogong_div").show();
-					$("#no_nanogong_div").hide();
-					is_nano = 1;
-					$(".nanogong_player").show();
-				} else {
-					$("#no_nanogong_div").show();
-					$("#nanogong_div").hide();
-					$(".nanogong_player").hide();
-				}
-
-				//show always the mp3/ogg upload form (for dev purposes)
-
-				//$("#no_nanogong_div").show();
-				//$("#nanogong_div").hide();
-			});
-
-			function delete_file() {
-				$.ajax({
-					url: "'.$url_delete.'",
-					success:function(data) {
-						$("#status_warning").hide();
-						$("#status_ok").hide();
-
-						$("#messages").html(data);
-						$("#messages").show();
-						$("#preview").hide();
-					}
-				});
-			}
-
-			function upload_file() {
-				$("#form_nanogong_simple").submit();
-			}
-
-			function send_voice() {
-				$("#status_warning").hide();
-				$("#status_ok").hide();
-				$("#messages").hide();
-
-				var check_js = check_gong();
-				var recorder = document.getElementById("nanogong");
-
-				if (!recorder || !check_js) {
-					//alert(lang_no_applet)
-					$("#status_warning").html(lang_no_applet);
-					$("#status_warning").show();
-
-                    //Show form
-                    $("#no_nanogong_div").show();
-                    $("#nanogong_div").hide();
-					return false;
-				}
-
-				var duration = parseInt(recorder.sendGongRequest("GetMediaDuration", "audio")) || 0;
-
-				if (duration <= 0) {
-					$("#status_warning").html(lang_record_before_save);
-					$("#status_warning").show();
-					return false;
-				}
-
-				var applet = document.getElementById("nanogong");
-
-				var ret = applet.sendGongRequest("PostToForm", "'.$url.'", "file", "", "temp"); // PostToForm, postURL, inputname, cookie, filename
-
-				if (ret == 1)  {
-					$("#status_ok").html(lang_submitted);
-					$("#status_ok").show();
-					$.ajax({
-						url:"'.$url_load_file.'&is_nano="+is_nano,
-						success: function(data){
-							$("#preview").html(data);
-							$("#preview").show();
-						}
-					});
-				} else {
-					//alert(lang_submitted+"\n"+ret);
-					$("#status_warning").html(lang_failed_to_submit);
-					$("#status_warning").show();
-				}
-				return false;
-			}
-			</script>';
-		return $js;
-	}
-
-	/**
-	 * Returns the HTML form to upload a nano file or upload a file
-     * @param string
-	 */
-	public function return_form($message = null)
-    {
-
-		$params = $this->get_params(true);
-		$url = api_get_path(WEB_AJAX_PATH).'nanogong.ajax.php?a=save_file&'.$params;
-
-		//check browser support and load form
-		$array_browser = api_browser_support('check_browser');
-
-		$preview_file = $this->show_audio_file(true, true);
-
-        $preview_file = Display::div(
-            $preview_file,
-            array('id' => 'preview', 'style' => 'text-align:center; padding-left: 25px;')
-        );
-
-		$html = '<center>';
-
-		//Use normal upload file
-		$html .= Display::return_icon('microphone.png', get_lang('PressRecordButton'),'', ICON_SIZE_BIG);
-		$html .='<br />';
-
-		$html .= '<div id="nanogong_div">';
-
-		$html .= '<applet id="nanogong" archive="'.api_get_path(WEB_LIBRARY_PATH).'nanogong/nanogong.jar" code="gong.NanoGong" width="250" height="95" align="middle">';
-		//echo '<param name="ShowRecordButton" value="false" />'; // default true
-		// echo '<param name="ShowSaveButton" value="false" />'; //you can save in local computer | (default true)
-        $html .= '<param name="ShowSpeedButton" value="false" />'; // default true
-		//echo '<param name="ShowAudioLevel" value="false" />'; //  it displays the audiometer | (default true)
-		$html .= '<param name="ShowTime" value="true" />'; // default false
-		$html .= '<param name="Color" value="#FFFFFF" />'; // default #FFFFFF
-		//echo '<param name="StartTime" value="10.5" />';
-		//echo '<param name="EndTime" value="65" />';
-		$html .= '<param name="AudioFormat" value="ImaADPCM" />';// ImaADPCM (more speed), Speex (more compression)|(default Speex)
-		//$html .= '<param name="AudioFormat" value="Speex" />';// ImaADPCM (more speed), Speex (more compression)|(default Speex)
-
-		//echo '<param name="SamplingRate" value="32000" />';//Quality for ImaADPCM (low 8000, medium 11025, normal 22050, hight 44100) OR Quality for Speex (low 8000, medium 16000, normal 32000, hight 44100) | (default 44100)
-		//echo '<param name="MaxDuration" value="60" />';
-		//echo '<param name="SoundFileURL" value="http://somewhere.com/mysoundfile.wav" />';//load a file |(default "")
-		$html .= '</applet>';
-
-		$html .= '<br /><br /><br />';
-
-        $html .= '<form name="form_nanogong_advanced">';
-		$html .= '<input type="hidden" name="is_nano" value="1">';
-		$html .= '<a href="#" class="btn btn-default"  onclick="send_voice()" />'.get_lang('SendRecord').'</a>';
-		$html .= '</form></div>';
-
-        $html .= Display::url(get_lang('ProblemsRecordingUploadYourOwnAudioFile'), 'javascript:void(0)', array('onclick' => 'show_simple_upload_form();'));
-
-		$html .= '<br /><br /><div id="no_nanogong_div">';
-		//$html .= Display::return_message(get_lang('BrowserNotSupportNanogongSend'), 'warning');
-		$html .= '<form id="form_nanogong_simple" class="form-search" action="'.$url.'" name="form_nanogong" method="POST" enctype="multipart/form-data">';
-		$html .= '<input type="file" name="file">';
-		$html .= '<a href="#" class="btn btn-default"  onclick="upload_file()" /><em class="fa fa-upload"></em> '.get_lang('UploadFile').'</a>';
-		$html .= '</form>';
-        $html .= '</div>';
-		$html .= '</center>';
-		$html .= '<div style="display:none" id="status_ok" class="confirmation-message"></div><div style="display:none" id="status_warning" class="warning-message"></div>';
-		$html .= '<div id="messages">'.$message.'</div>';
-		$html .= $preview_file;
-
-		return $html;
-	}
-
-    /**
-     * @param bool $return_as_query
-     * @return bool|string
-     */
-    public function get_params($return_as_query = false)
-    {
-		if (empty($this->params)) {
-			return false;
-		}
-		if ($return_as_query) {
-			return http_build_query($this->params);
-		}
-
-		return $this->params;
-	}
-
-    /**
-     * @param $attribute
-     * @return mixed
-     */
-    public function get_param_value($attribute)
-    {
-		if (isset($this->params[$attribute])) {
-			return $this->params[$attribute];
-		}
-	}
-
-	/**
-	 * Show a button to load the form
-	 * @return string
-	 */
-    public function show_button()
-    {
-		$params_string = $this->get_params(true);
-
-        $url = api_get_path(WEB_AJAX_PATH)
-            . 'nanogong.ajax.php?a=show_form&'
-            . $params_string
-            . '&TB_iframe=true';
-
-        $html = Display::url(
-            get_lang('RecordAnswer'),
-            $url,
-            [
-                'class' => 'btn btn-default ajax',
-                'data-title' => get_lang('RecordAnswer')
-            ]
-        );
-		$html .= '<br /><br />'.Display::return_message(get_lang('UseTheMessageBelowToAddSomeComments'));
-		return $html;
-	}
-}

+ 139 - 0
main/template/default/exercise/oral_expression.tpl

@@ -0,0 +1,139 @@
+<div class="alert alert-warning">
+    <span class="fa fa-warning fa-fw" aria-hidden="true"></span> {{ 'WamiNeedFilename'|get_lang }}
+</div>
+
+<div id="record-audio-recordrtc" class="row text-center">
+    <form>
+        <div class="row">
+            <div class="col-sm-4 col-sm-offset-4">
+                <div class="form-group">
+                    <span class="fa fa-microphone fa-5x fa-fw" aria-hidden="true"></span>
+                    <span class="sr-only">{{ 'RecordAudio'|get_lang }}</span>
+                </div>
+            </div>
+            <div class="col-sm-12">
+                <div class="form-groups">
+                    <button class="btn btn-primary" type="button" id="btn-start-record">
+                        <span class="fa fa-circle fa-fw" aria-hidden="true"></span> {{ 'StartRecordingAudio'|get_lang }}
+                    </button>
+                    <button class="btn btn-success" type="button" id="btn-stop-record" disabled>
+                        <span class="fa fa-square fa-fw" aria-hidden="true"></span> {{ 'StopRecordingAudio'|get_lang }}
+                    </button>
+                </div>
+            </div>
+        </div>
+    </form>
+</div>
+
+<div class="row" id="record-audio-wami">
+    <div class="col-sm-4 col-sm-offset-4 text-center">
+        <div id="record-audio-wami-container" class="wami-container"></div>
+    </div>
+</div>
+
+<script>
+    $(document).on('ready', function () {
+        function useRecordRTC() {
+            $('#record-audio-recordrtc').show();
+            var mediaConstraints = {audio: true},
+                    recordRTC = null,
+                    btnStart = $('#btn-start-record'),
+                    btnStop = $('#btn-stop-record');
+
+            btnStart.on('click', function () {
+                navigator.getUserMedia = navigator.getUserMedia ||
+                        navigator.mozGetUserMedia ||
+                        navigator.webkitGetUserMedia;
+
+                if (navigator.getUserMedia) {
+                    navigator.getUserMedia(mediaConstraints, successCallback, errorCallback);
+                } else if (navigator.mediaDevices.getUserMedia) {
+                    navigator.mediaDevices.getUserMedia(mediaConstraints)
+                            .then(successCallback).error(errorCallback);
+                }
+
+                function successCallback(stream) {
+                    recordRTC = RecordRTC(stream, {
+                        numberOfAudioChannels: 1,
+                        type: 'audio'
+                    });
+                    recordRTC.startRecording();
+
+                    btnStop.prop('disabled', false);
+                    btnStart.prop('disabled', true);
+                }
+
+                function errorCallback(error) {
+                    alert(error.message);
+                }
+            });
+
+            btnStop.on('click', function () {
+                if (!recordRTC) {
+                    return;
+                }
+
+                recordRTC.stopRecording(function (audioURL) {
+                    var recordedBlob = recordRTC.getBlob(),
+                            fileName = '{{ file_name }}',
+                            fileExtension = '.' + recordedBlob.type.split('/')[1];
+
+                    var formData = new FormData();
+                    formData.append('audio_blob', recordedBlob, fileName + fileExtension);
+                    formData.append('audio_dir', '{{ directory }}');
+
+                    $.ajax({
+                        url: '{{ _p.web_ajax }}record_audio_rtc.ajax.php',
+                        data: formData,
+                        processData: false,
+                        contentType: false,
+                        type: 'POST'
+                    });
+
+                    btnStop.prop('disabled', true);
+                    btnStart.prop('disabled', false);
+                });
+            });
+        }
+
+        function useWami() {
+            $('#record-audio-wami').show();
+
+            Wami.setup({
+                id: "record-audio-wami-container",
+                onReady: setupGUI,
+                swfUrl: '{{ _p.web_lib }}wami-recorder/Wami.swf'
+            });
+
+            function setupGUI() {
+                var gui = new Wami.GUI({
+                        id: 'record-audio-wami-container',
+                        singleButton: true,
+                        recordUrl: '{{ _p.web_ajax }}record_audio_wami.ajax.php?' + $.param({
+                            waminame: '{{ file_name }}.wav',
+                            wamidir: '{{ directory }}',
+                            wamiuserid: {{ user_id }}
+                        }),
+                        buttonUrl: '{{ _p.web_lib }}wami-recorder/buttons.png',
+                        buttonNoUrl: '{{ _p.web_img }}blank.gif'
+                    }
+                );
+
+                gui.setPlayEnabled(false);
+            }
+        }
+
+        $('#record-audio-recordrtc, #record-audio-wami').hide();
+
+        var webRTCIsEnabled = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia ||
+                navigator.mediaDevices.getUserMedia;
+
+        if (webRTCIsEnabled) {
+            useRecordRTC();
+
+            return;
+        }
+
+        useWami();
+    });
+</script>