VirtualBox

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

Last change on this file since 89234 was 89226, checked in by vboxsync, 4 years ago

Audio/ValKit: Initial support for the audio test execution service (ATS) to support playing test tones. bugref:10008

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.0 KB
Line 
1/* $Id: AudioTestServiceClient.cpp 89226 2021-05-21 15:02:10Z vboxsync $ */
2/** @file
3 * AudioTestServiceClient - Audio test execution server, 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.virtualbox.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
36typedef struct ATSSRVREPLY
37{
38 char szOp[8];
39 void *pvPayload;
40 size_t cbPayload;
41
42} ATSSRVREPLY;
43typedef struct ATSSRVREPLY *PATSSRVREPLY;
44
45
46static void audioTestSvcClientConnInit(PATSCLIENT pClient)
47{
48 pClient->cbHdr = 0;
49 pClient->hSock = NIL_RTSOCKET;
50}
51
52static void audioTestSvcClientReplyFree(PATSSRVREPLY pReply)
53{
54 if (!pReply)
55 return;
56
57 if (pReply->pvPayload)
58 {
59 Assert(pReply->cbPayload);
60 RTMemFree(pReply->pvPayload);
61 pReply->pvPayload = NULL;
62 }
63
64 pReply->cbPayload = 0;
65}
66
67static int audioTestSvcClientRecvReply(PATSCLIENT pClient, PATSSRVREPLY pReply, bool fNoDataOk)
68{
69 int rc;
70
71 ATSPKTHDR Hdr;
72 size_t cbHdr = 0;
73 if (pClient->cbHdr)
74 {
75 memcpy(&Hdr, &pClient->abHdr, sizeof(Hdr));
76 cbHdr = pClient->cbHdr;
77 pClient->cbHdr = 0;
78 rc = VINF_SUCCESS;
79 }
80 else
81 rc = RTTcpRead(pClient->hSock, &Hdr, sizeof(Hdr), &cbHdr);
82
83 /** @todo Use defines for all those numbers below. */
84
85 if (cbHdr != 16)
86 return VERR_NET_PROTOCOL_ERROR;
87
88 if (RT_SUCCESS(rc))
89 {
90 if (Hdr.cb < 16)
91 return VERR_NET_PROTOCOL_ERROR;
92
93 if (Hdr.cb > 1024 * 1024)
94 return VERR_NET_PROTOCOL_ERROR;
95
96 /** @todo Check opcode encoding. */
97
98 if (Hdr.cb > 16)
99 {
100 uint32_t cbPadding;
101 if (Hdr.cb % 16)
102 cbPadding = 16 - (Hdr.cb % 16);
103 else
104 cbPadding = 0;
105
106 pReply->pvPayload = RTMemAlloc(Hdr.cb - 16);
107 pReply->cbPayload = Hdr.cb - 16;
108
109 size_t cbRead = 0;
110 rc = RTTcpRead(pClient->hSock, pReply->pvPayload, RT_MIN(Hdr.cb - 16 + cbPadding, pReply->cbPayload), &cbRead);
111 if (RT_SUCCESS(rc))
112 {
113 if (!cbRead)
114 {
115 memcpy(&pClient->abHdr, &Hdr, sizeof(pClient->abHdr));
116 if (!fNoDataOk)
117 rc = VERR_NET_PROTOCOL_ERROR;
118 }
119 else
120 {
121 while (cbPadding--)
122 {
123 Assert(cbRead);
124 cbRead--;
125 }
126 }
127
128 if (RT_SUCCESS(rc))
129 {
130 /** @todo Check CRC-32. */
131
132 memcpy(pReply->szOp, Hdr.achOpcode, sizeof(pReply->szOp));
133 pReply->cbPayload = cbRead;
134
135 /** @todo Re-allocate pvPayload to not store padding? */
136 }
137 }
138
139 if (RT_FAILURE(rc))
140 audioTestSvcClientReplyFree(pReply);
141 }
142 }
143
144 return rc;
145}
146
147static int audioTestSvcClientRecvAck(PATSCLIENT pClient)
148{
149 ATSSRVREPLY Reply;
150 RT_ZERO(Reply);
151
152 int rc = audioTestSvcClientRecvReply(pClient, &Reply, true /* fNoDataOk */);
153 if (RT_SUCCESS(rc))
154 {
155 if (RTStrNCmp(Reply.szOp, "ACK ", 8) != 0) /** @todo Use protocol define. */
156 rc = VERR_NET_PROTOCOL_ERROR;
157
158 audioTestSvcClientReplyFree(&Reply);
159 }
160
161 return rc;
162}
163
164static int audioTestSvcClientSend(PATSCLIENT pClient, const void *pvData, size_t cbData)
165{
166 return RTTcpWrite(pClient->hSock, pvData, cbData);
167}
168
169static int audioTestSvcClientSendMsg(PATSCLIENT pClient,
170 void *pvHdr, size_t cbHdr, const void *pvPayload, size_t cbPayload)
171{
172 int rc = audioTestSvcClientSend(pClient, pvHdr, cbHdr);
173 if ( RT_SUCCESS(rc)
174 && cbPayload)
175 {
176 rc = audioTestSvcClientSend(pClient, (uint8_t *)pvPayload, cbPayload);
177 }
178
179 return rc;
180}
181
182DECLINLINE (void) audioTestSvcClientReqHdrInit(PATSPKTHDR pReqHdr, size_t cbReq, const char *pszOp, size_t cbPayload)
183{
184 AssertReturnVoid(strlen(pszOp) >= 2);
185
186 /** @todo Validate opcode. */
187
188 memcpy(pReqHdr->achOpcode, pszOp, sizeof(pReqHdr->achOpcode));
189 pReqHdr->uCrc32 = 0; /** @todo Do CRC-32 calculation. */
190 pReqHdr->cb = (uint32_t)cbReq + (uint32_t)cbPayload;
191}
192
193static int audioTestSvcClientDoGreet(PATSCLIENT pClient)
194{
195 ATSPKTREQHOWDY Req;
196 Req.uVersion = ATS_PROTOCOL_VS;
197 audioTestSvcClientReqHdrInit(&Req.Hdr, sizeof(Req), ATSPKT_OPCODE_HOWDY, 0);
198 int rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req), NULL, 0);
199 if (RT_SUCCESS(rc))
200 rc = audioTestSvcClientRecvAck(pClient);
201 return rc;
202}
203
204static int audioTestSvcClientDoBye(PATSCLIENT pClient)
205{
206 ATSPKTHDR Hdr;
207 audioTestSvcClientReqHdrInit(&Hdr, sizeof(Hdr), ATSPKT_OPCODE_BYE, 0);
208 int rc = audioTestSvcClientSendMsg(pClient, &Hdr, sizeof(Hdr), NULL, 0);
209 if (RT_SUCCESS(rc))
210 rc = audioTestSvcClientRecvAck(pClient);
211
212 return rc;
213}
214
215int AudioTestSvcClientConnect(PATSCLIENT pClient, const char *pszAddr)
216{
217 audioTestSvcClientConnInit(pClient);
218
219 /* For simplicity we always run on the same port, localhost only. */
220 int rc = RTTcpClientConnect(pszAddr ? pszAddr : "127.0.0.1", 6052, &pClient->hSock);
221 if (RT_SUCCESS(rc))
222 {
223 rc = audioTestSvcClientDoGreet(pClient);
224 }
225
226 return rc;
227}
228
229int AudioTestSvcClientTonePlay(PATSCLIENT pClient, PPDMAUDIOSTREAMCFG pStreamCfg, PAUDIOTESTTONEPARMS pToneParms)
230{
231 ATSPKTREQTONEPLAY Req;
232
233 memcpy(&Req.StreamCfg, pStreamCfg, sizeof(PDMAUDIOSTREAMCFG));
234 memcpy(&Req.ToneParms, pToneParms, sizeof(AUDIOTESTTONEPARMS));
235
236 audioTestSvcClientReqHdrInit(&Req.Hdr, sizeof(Req), ATSPKT_OPCODE_TONE_PLAY, 0);
237
238 int rc = audioTestSvcClientSendMsg(pClient, &Req, sizeof(Req), NULL, 0);
239 if (RT_SUCCESS(rc))
240 rc = audioTestSvcClientRecvAck(pClient);
241
242 return rc;
243}
244
245int AudioTestSvcClientClose(PATSCLIENT pClient)
246{
247 int rc = audioTestSvcClientDoBye(pClient);
248 if (RT_SUCCESS(rc))
249 rc = RTTcpClientClose(pClient->hSock);
250
251 return rc;
252}
253
Note: See TracBrowser for help on using the repository browser.

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