VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/AudioTestServiceClient.cpp@ 89382

最後變更 在這個檔案從89382是 89285,由 vboxsync 提交於 4 年 前

Audio/ValKit: Docs. bugref:10008

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 10.2 KB
 
1/* $Id: AudioTestServiceClient.cpp 89285 2021-05-26 07:43:27Z vboxsync $ */
2/** @file
3 * AudioTestServiceClient - Audio Test Service (ATS), Client helpers.
4 *
5 * Note: Only does TCP/IP as transport layer for now.
6 */
7
8/*
9 * Copyright (C) 2021 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.alldomusa.eu.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#define LOG_GROUP RTLOGGROUP_DEFAULT
25#include <iprt/crc.h>
26#include <iprt/err.h>
27#include <iprt/mem.h>
28#include <iprt/string.h>
29#include <iprt/tcp.h>
30
31#include "AudioTestServiceProtocol.h"
32#include "AudioTestServiceClient.h"
33
34/** @todo Use common defines between server protocol and this client. */
35
36/**
37 * A generic ATS reply, used by the client
38 * to process the incoming packets.
39 */
40typedef struct ATSSRVREPLY
41{
42 char szOp[8];
43 void *pvPayload;
44 size_t cbPayload;
45} ATSSRVREPLY;
46/** Pointer to a generic ATS reply. */
47typedef struct ATSSRVREPLY *PATSSRVREPLY;
48
49
50/**
51 * Initializes an ATS client, internal version.
52 *
53 * @param pClient Client to initialize.
54 */
55static void audioTestSvcClientInit(PATSCLIENT pClient)
56{
57 pClient->cbHdr = 0;
58 pClient->hSock = NIL_RTSOCKET;
59}
60
61/**
62 * Free's an ATS server reply.
63 * @param pReply Reply to free. The pointer is invalid afterwards.
64 */
65static void audioTestSvcClientReplyFree(PATSSRVREPLY pReply)
66{
67 if (!pReply)
68 return;
69
70 if (pReply->pvPayload)
71 {
72 Assert(pReply->cbPayload);
73 RTMemFree(pReply->pvPayload);
74 pReply->pvPayload = NULL;
75 }
76
77 pReply->cbPayload = 0;
78}
79
80/**
81 * Receives a reply from an ATS server.
82 *
83 * @returns VBox status code.
84 * @param pClient Client to receive reply for.
85 * @param pReply Where to store the reply.
86 * @param fNoDataOk If it's okay that the reply is not expected to have any payload.
87 */
88static int audioTestSvcClientRecvReply(PATSCLIENT pClient, PATSSRVREPLY pReply, bool fNoDataOk)
89{
90 int rc;
91
92 ATSPKTHDR Hdr;
93 size_t cbHdr = 0;
94 if (pClient->cbHdr)
95 {
96 memcpy(&Hdr, &pClient->abHdr, sizeof(Hdr));
97 cbHdr = pClient->cbHdr;
98 pClient->cbHdr = 0;
99 rc = VINF_SUCCESS;
100 }
101 else
102 rc = RTTcpRead(pClient->hSock, &Hdr, sizeof(Hdr), &cbHdr);
103
104 /** @todo Use defines for all those numbers below. */
105
106 if (cbHdr != 16)
107 return VERR_NET_PROTOCOL_ERROR;
108
109 if (RT_SUCCESS(rc))
110 {
111 if (Hdr.cb < 16)
112 return VERR_NET_PROTOCOL_ERROR;
113
114 if (Hdr.cb > 1024 * 1024)
115 return VERR_NET_PROTOCOL_ERROR;
116
117 /** @todo Check opcode encoding. */
118
119 if (Hdr.cb > 16)
120 {
121 uint32_t cbPadding;
122 if (Hdr.cb % 16)
123 cbPadding = 16 - (Hdr.cb % 16);
124 else
125 cbPadding = 0;
126
127 pReply->pvPayload = RTMemAlloc(Hdr.cb - 16);
128 pReply->cbPayload = Hdr.cb - 16;
129
130 size_t cbRead = 0;
131 rc = RTTcpRead(pClient->hSock, pReply->pvPayload, RT_MIN(Hdr.cb - 16 + cbPadding, pReply->cbPayload), &cbRead);
132 if (RT_SUCCESS(rc))
133 {
134 if (!cbRead)
135 {
136 memcpy(&pClient->abHdr, &Hdr, sizeof(pClient->abHdr));
137 if (!fNoDataOk)
138 rc = VERR_NET_PROTOCOL_ERROR;
139 }
140 else
141 {
142 while (cbPadding--)
143 {
144 Assert(cbRead);
145 cbRead--;
146 }
147 }
148
149 if (RT_SUCCESS(rc))
150 {
151 /** @todo Check CRC-32. */
152
153 memcpy(pReply->szOp, Hdr.achOpcode, sizeof(pReply->szOp));
154 pReply->cbPayload = cbRead;
155
156 /** @todo Re-allocate pvPayload to not store padding? */
157 }
158 }
159
160 if (RT_FAILURE(rc))
161 audioTestSvcClientReplyFree(pReply);
162 }
163 }
164
165 return rc;
166}
167
168/**
169 * Receives a reply for an ATS server and checks if it is an acknowledge (success) one.
170 *
171 * @returns VBox status code.
172 * @retval VERR_NET_PROTOCOL_ERROR if the reply indicates a failure.
173 * @param pClient Client to receive reply for.
174 */
175static int audioTestSvcClientRecvAck(PATSCLIENT pClient)
176{
177 ATSSRVREPLY Reply;
178 RT_ZERO(Reply);
179
180 int rc = audioTestSvcClientRecvReply(pClient, &Reply, true /* fNoDataOk */);
181 if (RT_SUCCESS(rc))
182 {
183 if (RTStrNCmp(Reply.szOp, "ACK ", 8) != 0) /** @todo Use protocol define. */
184 rc = VERR_NET_PROTOCOL_ERROR;
185
186 audioTestSvcClientReplyFree(&Reply);
187 }
188
189 return rc;
190}
191
192/**
193 * Sends data over the transport to the server.
194 * For now only TCP/IP is implemented.
195 *
196 * @returns VBox status code.
197 * @param pClient Client to send data for.
198 * @param pvData Pointer to data to send.
199 * @param cbData Size (in bytes) of \a pvData to send.
200 */
201static int audioTestSvcClientSend(PATSCLIENT pClient, const void *pvData, size_t cbData)
202{
203 return RTTcpWrite(pClient->hSock, pvData, cbData);
204}
205
206/**
207 * Sends a message plus optional payload to an ATS server.
208 *
209 * @returns VBox status code.
210 * @param pClient Client to send message for.
211 * @param pvHdr Pointer to header data to send.
212 * @param cbHdr Size (in bytes) of \a pvHdr to send.
213 * @param pvPayload Pointer to payload to send. Optional.
214 * @param cbPayload Size (in bytes) of \a pvPayload to send. Set to 0 if no payload needed.
215 */
216static int audioTestSvcClientSendMsg(PATSCLIENT pClient,
217 void *pvHdr, size_t cbHdr, const void *pvPayload, size_t cbPayload)
218{
219 int rc = audioTestSvcClientSend(pClient, pvHdr, cbHdr);
220 if ( RT_SUCCESS(rc)
221 && cbPayload)
222 {
223 rc = audioTestSvcClientSend(pClient, (uint8_t *)pvPayload, cbPayload);
224 }
225
226 return rc;
227}
228
229/**
230 * Initializes a client request header.
231 *
232 * @returns VBox status code.
233 * @param pReqHdr Request header to initialize.
234 * @param cbReq Size (in bytes) the request will have (does *not* include payload).
235 * @param pszOp Operation to perform with the request.
236 * @param cbPayload Size (in bytes) of payload that will follow the header. Optional and can be 0.
237 */
238DECLINLINE (void) audioTestSvcClientReqHdrInit(PATSPKTHDR pReqHdr, size_t cbReq, const char *pszOp, size_t cbPayload)
239{
240 AssertReturnVoid(strlen(pszOp) >= 2);
241
242 /** @todo Validate opcode. */
243
244 memcpy(pReqHdr->achOpcode, pszOp, sizeof(pReqHdr->achOpcode));
245 pReqHdr->uCrc32 = 0; /** @todo Do CRC-32 calculation. */
246 pReqHdr->cb = (uint32_t)cbReq + (uint32_t)cbPayload;
247}
248
249/**
250 * Sends a greeting command (handshake) to an ATS server.
251 *
252 * @returns VBox status code.
253 * @param pClient Client to send command for.
254 */
255static int audioTestSvcClientDoGreet(PATSCLIENT pClient)
256{
257 ATSPKTREQHOWDY Req;
258 Req.uVersion = ATS_PROTOCOL_VS;
259 audioTestSvcClientReqHdrInit(&Req.Hdr, sizeof(Req), ATSPKT_OPCODE_HOWDY, 0);
260 int rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req), NULL, 0);
261 if (RT_SUCCESS(rc))
262 rc = audioTestSvcClientRecvAck(pClient);
263 return rc;
264}
265
266/**
267 * Sends a disconnect command to an ATS server.
268 *
269 * @returns VBox status code.
270 * @param pClient Client to send command for.
271 */
272static int audioTestSvcClientDoBye(PATSCLIENT pClient)
273{
274 ATSPKTHDR Hdr;
275 audioTestSvcClientReqHdrInit(&Hdr, sizeof(Hdr), ATSPKT_OPCODE_BYE, 0);
276 int rc = audioTestSvcClientSendMsg(pClient, &Hdr, sizeof(Hdr), NULL, 0);
277 if (RT_SUCCESS(rc))
278 rc = audioTestSvcClientRecvAck(pClient);
279
280 return rc;
281}
282
283/**
284 * Connects to an ATS server.
285 *
286 * @returns VBox status code.
287 * @param pClient Client to connect.
288 * @param pszAddr Address to connect to. If NULL, 127.0.0.1 (localhost) will be used.
289 * @note The port (6052) is hardcoded for simplicity for now.
290 */
291int AudioTestSvcClientConnect(PATSCLIENT pClient, const char *pszAddr)
292{
293 audioTestSvcClientInit(pClient);
294
295 /* For simplicity we always run on the same port, localhost only. */
296 int rc = RTTcpClientConnect(pszAddr ? pszAddr : "127.0.0.1", 6052, &pClient->hSock);
297 if (RT_SUCCESS(rc))
298 {
299 rc = audioTestSvcClientDoGreet(pClient);
300 }
301
302 return rc;
303}
304
305/**
306 * Tells the server to play a (test) tone.
307 *
308 * @returns VBox status code.
309 * @param pClient Client to issue command for.
310 * @param pStreamCfg Audio stream configuration to use.
311 * @param pToneParms Tone parameters to use.
312 * @note How (and if) the server plays a tone depends on the actual implementation side.
313 */
314int AudioTestSvcClientTonePlay(PATSCLIENT pClient, PPDMAUDIOSTREAMCFG pStreamCfg, PAUDIOTESTTONEPARMS pToneParms)
315{
316 ATSPKTREQTONEPLAY Req;
317
318 memcpy(&Req.StreamCfg, pStreamCfg, sizeof(PDMAUDIOSTREAMCFG));
319 memcpy(&Req.ToneParms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
320
321 audioTestSvcClientReqHdrInit(&Req.Hdr, sizeof(Req), ATSPKT_OPCODE_TONE_PLAY, 0);
322
323 int rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req), NULL, 0);
324 if (RT_SUCCESS(rc))
325 rc = audioTestSvcClientRecvAck(pClient);
326
327 return rc;
328}
329
330/**
331 * Disconnects from an ATS server.
332 *
333 * @returns VBox status code.
334 * @param pClient Client to disconnect.
335 */
336int AudioTestSvcClientClose(PATSCLIENT pClient)
337{
338 int rc = audioTestSvcClientDoBye(pClient);
339 if (RT_SUCCESS(rc))
340 rc = RTTcpClientClose(pClient->hSock);
341
342 return rc;
343}
344
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette