\chapter{Audio Chat}


\section{Voice recording}
Since we are using vuejs, so we will use web api to do this job.

\subsection{HTML}
\lstinputlisting[language=HTML]{data/codes/11/index.html}

\subsection{Javascript}
\lstinputlisting[language=Python]{data/codes/11/index.js}


\section{Audio transferring}
We have to change our database data structure first to do this job. Because for now, we are not only doing text transferring, we were doing audio transferring. Or to be specific, we were doing arbitrary file transferring. We have to treat the text or audio as a general file.


\subsection{Change in data structure}
The original databse data struct is:

\begin{lstlisting}
     "history": [
         {
             "date": date,
             "from": from_,
             "to": to_,
             "text": text,
         }
     ]
\end{lstlisting}

Now it should be:

\begin{lstlisting}
     "history": [
         {
            "date": date,
            "from": from_,
            "to": to_,
            "content": {
                "type":,
                "name":,
                "file_id":,
            },
         }
     ]
\end{lstlisting}

The \textbf{type} here is indicating the file type, if it's an audio, we play it, if it's a text, we show it.

The \textbf{name} here is indicating the file name without doubt.

The \textbf{content-id} here is indicating the id of a file that has been saved in out database. By the way, we use 'GridFS' to save our file to mongodb. ('GridFS' is a Python library here.)


\subsection{Change in API requiring}
Since the server won't know what kind of file the user send to it. The user needs to specify the file-type and file-name by itself. That's exactly what the following code did:

\begin{lstlisting}
    if the_user_we_found != None:
        from_ = username
        to = body.get("to")
        content = body.get("content")
        if to and content:
            type_ = content.get("type")
            name_ = content.get("name")
            file_ = content.get("file")
            if type_ and name_ and file_:
                result["status"] = "ok"
                file_bytes = file_.encode("utf-8")
                file_id = file_system.put(file_bytes)
                update_an_conversation(from_, to, type_, name_, file_id)
\end{lstlisting}

And there has another problem, by doing so far, the user or client can only get the \textbf{file-id}, it won't get the real binary file. So it has to do another request to get the real file from the server by sending the file-id to that server:

\begin{lstlisting}
    @app.route('/api/v1/file', methods=['POST'])
    async def receive(request):
        data = request.json
        result = {"status": "wrong"}
        if data:
            username = data.get("username")
            temp_token = data.get("temp_token")
            body = data.get("body")
            if username and temp_token and body:
                the_user_we_found = users.find_one({"username": username, "temp_token": temp_token})
                if the_user_we_found != None:
                    file_id = body.get("file_id")
                    if file_id:
                        obj_file_id = ObjectId(file_id)
                        if file_system.exists(obj_file_id):
                            bytes_of_that_file = file_system.get(obj_file_id).read()
                            result["status"] = "ok"
                            result["result"] = bytes_of_that_file.decode("utf-8")
                        else:
                            result["status"] = f"wrong: no such a file with the name of {file_id}"
                    else:
                        result["status"] = "wrong: 'file_id' not found at 'body'"
                else:
                    result["status"] = "wrong: no such account or wrong temp_token"
        return response.json(result, dumps=my_json_dumps)
\end{lstlisting}


\section{Screenshot}
\subsection{User 1}
\includegraphics[scale=0.2]{figures/the_audio_chat_page1.png}%
\subsection{User 2}
\includegraphics[scale=0.2]{figures/the_audio_chat_page2.png}%