1 /* 2 * ESounD media addon for BeOS 3 * 4 * Copyright (c) 2006 François Revol (revol@free.fr) 5 * 6 * Based on Multi Audio addon for Haiku, 7 * Copyright (c) 2002, 2003 Jerome Duval (jerome.duval@free.fr) 8 * 9 * All rights reserved. 10 * Redistribution and use in source and binary forms, with or without modification, 11 * are permitted provided that the following conditions are met: 12 * 13 * - Redistributions of source code must retain the above copyright notice, 14 * this list of conditions and the following disclaimer. 15 * - Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 25 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 */ 31 #define _ZETA_TS_FIND_DIR_ 1 32 #include <FindDirectory.h> 33 #include <File.h> 34 #include <Path.h> 35 #include <sys/socket.h> 36 #include <arpa/inet.h> 37 #include <netdb.h> 38 #include <netinet/in.h> 39 #include <netinet/tcp.h> 40 #include <errno.h> 41 #include <stdlib.h> 42 #include "compat.h" 43 //#undef DEBUG 44 //#define DEBUG 4 45 #include "debug.h" 46 #include <Debug.h> 47 #include "ESDEndpoint.h" 48 49 ESDEndpoint::ESDEndpoint() 50 : BDataIO() 51 , fHost(NULL) 52 , fPort(ESD_PORT) 53 , fSocket(-1) 54 , fDefaultCommand(ESD_CMD_STREAM_PLAY) 55 , fDefaultCommandSent(false) 56 , fDefaultFormat(ESD_BITS8 | ESD_MONO) 57 , fDefaultRate(ESD_DEFAULT_RATE) 58 , fLatency(0LL) 59 { 60 CALLED(); 61 } 62 63 ESDEndpoint::~ESDEndpoint() 64 { 65 CALLED(); 66 if (fSocket > -1) 67 closesocket(fSocket); 68 fSocket = -1; 69 } 70 71 status_t ESDEndpoint::SendAuthKey() 72 { 73 CALLED(); 74 BPath kfPath; 75 status_t err; 76 off_t size; 77 char key[ESD_MAX_KEY]; 78 err = find_directory(B_USER_SETTINGS_DIRECTORY, &kfPath); 79 kfPath.Append("esd_auth"); 80 BFile keyFile(kfPath.Path(), B_READ_WRITE|B_CREATE_FILE); 81 err = keyFile.GetSize(&size); 82 if (err < 0) 83 return err; 84 if (size < ESD_MAX_KEY) { 85 keyFile.Seek(0LL, SEEK_SET); 86 srand(time(NULL)); 87 for (int i = 0; i < ESD_MAX_KEY; i++) 88 key[i] = (char)(rand() % 256); 89 err = keyFile.Write(key, ESD_MAX_KEY); 90 if (err < 0) 91 return err; 92 if (err < ESD_MAX_KEY) 93 return EIO; 94 } 95 err = keyFile.Read(key, ESD_MAX_KEY); 96 if (err < 0) 97 return err; 98 if (err < ESD_MAX_KEY) 99 return EIO; 100 memcpy(fAuthKey, key, sizeof(esd_key_t)); 101 return write(fSocket, fAuthKey, ESD_MAX_KEY); 102 } 103 104 status_t ESDEndpoint::Connect(const char *host, uint16 port) 105 { 106 status_t err; 107 CALLED(); 108 fHost = host; 109 fPort = port; 110 111 struct hostent *he; 112 struct sockaddr_in sin; 113 he = gethostbyname(host); 114 PRINT(("gethostbyname(%s) = %p\n", host, he)); 115 if (!he) 116 return ENOENT; 117 memcpy((struct in_addr *)&sin.sin_addr, he->h_addr, sizeof(struct in_addr)); 118 119 fSocket = socket(AF_INET, SOCK_STREAM, 0); 120 if (fSocket < 0) 121 return errno; 122 sin.sin_family = AF_INET; 123 sin.sin_port = htons( port ); 124 125 err = connect(fSocket, (struct sockaddr *) &sin, sizeof(sin)); 126 PRINT(("connect: %s\n", strerror(err))); 127 if (err < 0) 128 return errno; 129 130 /* uint32 cmd = ESD_CMD_CONNECT; 131 err = write(fSocket, &cmd, sizeof(cmd)); 132 if (err < 0) 133 return errno; 134 if (err < sizeof(cmd)) 135 return EIO; 136 */ 137 err = SendAuthKey(); 138 if (err < 0) 139 return errno; 140 141 bigtime_t ping = system_time(); 142 143 uint32 endian = ESD_ENDIAN_TAG; 144 err = write(fSocket, &endian, sizeof(endian)); 145 if (err < 0) 146 return errno; 147 if (err < sizeof(endian)) 148 return EIO; 149 uint32 ok; 150 151 read(fSocket, &ok, sizeof(uint32)); 152 153 ping = system_time() - ping; 154 fLatency = ping; 155 156 int flag = 1; 157 setsockopt(fSocket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag)); 158 159 // read(fSocket, &ok, sizeof(uint32)); 160 // connect 161 // auth 162 // ask server latency 163 // calc network latency (time (send+recv) / 2) ? 164 // get default format 165 166 return B_OK; 167 } 168 169 status_t ESDEndpoint::Disconnect() 170 { 171 CALLED(); 172 if (fSocket > -1) 173 closesocket(fSocket); 174 fSocket = -1; 175 return B_OK; 176 } 177 178 status_t ESDEndpoint::SetCommand(esd_command_t cmd) 179 { 180 CALLED(); 181 if (fDefaultCommandSent) 182 return EALREADY; 183 fDefaultCommand = cmd; 184 return B_OK; 185 } 186 187 status_t ESDEndpoint::SetFormat(int bits, int channels, float rate) 188 { 189 esd_format_t fmt = 0; 190 CALLED(); 191 if (fDefaultCommandSent) 192 return EALREADY; 193 PRINT(("SetFormat(%d,%d,%d)\n", bits, channels, rate)); 194 switch (bits) { 195 case 8: 196 fmt |= ESD_BITS8; 197 break; 198 case 16: 199 fmt |= ESD_BITS16; 200 break; 201 default: 202 return EINVAL; 203 } 204 switch (channels) { 205 case 1: 206 fmt |= ESD_MONO; 207 break; 208 case 2: 209 fmt |= ESD_STEREO; 210 break; 211 default: 212 return EINVAL; 213 } 214 fmt |= ESD_STREAM | ESD_FUNC_PLAY; 215 PRINT(("SetFormat: %08lx\n", fmt)); 216 fDefaultFormat = fmt; 217 fDefaultRate = rate; 218 return B_OK; 219 } 220 221 status_t ESDEndpoint::GetServerInfo() 222 { 223 CALLED(); 224 struct serverinfo { 225 uint32 ver; 226 uint32 rate; 227 uint32 fmt; 228 } si; 229 status_t err; 230 err = SendCommand(ESD_CMD_SERVER_INFO, (const uint8 *)&si, 0, (uint8 *)&si, sizeof(si)); 231 if (err < 0) 232 return err; 233 PRINT(("err %d, version: %lu, rate: %lu, fmt: %lu\n", err, si.ver, si.rate, si.fmt)); 234 return B_OK; 235 } 236 237 bool ESDEndpoint::CanSend() 238 { 239 CALLED(); 240 return fDefaultCommandSent; 241 } 242 243 ssize_t ESDEndpoint::Read(void *buffer, size_t size) 244 { 245 CALLED(); 246 return EINVAL; 247 } 248 249 ssize_t ESDEndpoint::Write(const void *buffer, size_t size) 250 { 251 status_t err = B_OK; 252 CALLED(); 253 if (!fDefaultCommandSent) 254 err = SendDefaultCommand(); 255 if (err < B_OK) 256 return err; 257 //PRINT(("write(fSocket, buffer, %d)\n", size)); 258 //fprintf(stderr, "ESDEndpoint::Write(, %d) %s\n", size, (size%2)?"ODD BUFFER SIZE":""); 259 if (fDefaultFormat & ESD_BITS16) { 260 size /= 2; 261 size *= 2; 262 } 263 err = write(fSocket, buffer, size); 264 if (err != size) { 265 fprintf(stderr, "ESDEndpoint::Write: sent only %d of %d!\n", err, size); 266 } 267 //PRINT(("write(fSocket, buffer, %d): %s\n", size, strerror(err))); 268 if (err < B_OK) 269 return errno; 270 return err; 271 } 272 273 status_t ESDEndpoint::SendCommand(esd_command_t cmd, const uint8 *obuf, size_t olen, uint8 *ibuf, size_t ilen) 274 { 275 status_t err; 276 CALLED(); 277 err = send(fSocket, &cmd, sizeof(cmd), 0); 278 if (err < B_OK) 279 return errno; 280 if (obuf && olen) { 281 err = send(fSocket, obuf, olen, 0); 282 if (err < B_OK) 283 return errno; 284 } 285 err = B_OK; 286 if (ibuf && ilen) { 287 err = recv(fSocket, ibuf, ilen, 0); 288 if (err < B_OK) 289 return errno; 290 /* return received len */ 291 } 292 return err; 293 } 294 295 status_t ESDEndpoint::SendDefaultCommand() 296 { 297 status_t err; 298 struct { 299 esd_format_t format; 300 esd_rate_t rate; 301 char name[ESD_MAX_NAME]; 302 } c; 303 CALLED(); 304 if (fDefaultCommandSent) 305 return EALREADY; 306 c.format = fDefaultFormat; 307 c.rate = fDefaultRate; 308 strcpy(c.name, "BeOS/Haiku/ZETA Media Kit output"); 309 err = SendCommand(fDefaultCommand, (uint8 *)&c, sizeof(c), NULL, 0); 310 if (err < B_OK) 311 return err; 312 PRINT(("SendCommand: %s\n", strerror(err))); 313 fDefaultCommandSent = true; 314 return B_OK; 315 } 316 317