static size_t muroar_rsd_write(void *data, const void* buf, size_t size) { muroar_t *sound = data; if ( muroar_write(sound->fh, (void*)buf, size) != (ssize_t)size ) return 0; return size; }
// Close a control connection by sending QUIT command. int muroar_quit (muroar_t fh) { char quit[] = "\0\6\0\0\0\0\0\0\0\0"; // QUIT command int ret = 0; if ( fh == MUROAR_HANDLE_INVALID ) { _SET_ERRNO(EBADF); return -1; } if ( muroar_write(fh, quit, 10) != 10 ) ret = -1; // read in case the server response // ignore errors as the server do not necessary // response to our request. muroar_read(fh, quit, 10); if ( muroar_close(fh) == -1 ) ret = -1; return ret; }
// Open Control connection muroar_t muroar_connect(const char * server, const char * name) { char useraddr[80] = MUROAR_INVALID; char * addr[] = {useraddr, MUROAR_GSOCK, MUROAR_HOST, "::" MUROAR_OBJECT, MUROAR_ABSTRACT, NULL}; const char * home; unsigned char buf[MUROAR_IOBUF]; uint16_t tmpu16; uint16_t pid; muroar_t fh = MUROAR_HANDLE_INVALID; int i; #if !defined(__WIN32) ssize_t len; #endif // Prepare server address: if ( server != NULL && *server == 0 ) server = NULL; if ( server == NULL ) server = getenv("ROAR_SERVER"); #if !defined(__WIN32) if ( server == NULL ) { if ( (len = readlink("/etc/roarserver", useraddr, sizeof(useraddr))) != -1 ) { useraddr[len < (ssize_t)sizeof(useraddr) ? (size_t)len : sizeof(useraddr)-1] = 0; server = useraddr; } } #endif if ( server != NULL ) { // "+default" is an alias to NULL. if ( !strcmp(server, MUROAR_DEFAULT) ) { server = NULL; // "+invalid" always return an invalid handle. } else if ( !strcmp(server, MUROAR_INVALID) ) { #ifdef ECANCELED _SET_ERRNO(ECANCELED); #else _SET_ERRNO(EINVAL); #endif return MUROAR_HANDLE_INVALID; } } // Connect to server: if ( server != NULL ) { if ( (fh = muroar_open_socket(server)) == MUROAR_HANDLE_INVALID ) return MUROAR_HANDLE_INVALID; } else { // build string for ~/.roar home = getenv("HOME"); if ( home != NULL && home[0] == '/' && strlen(home) < (sizeof(useraddr) - 7) ) { snprintf(useraddr, sizeof(useraddr), "%s/.roar", home); useraddr[sizeof(useraddr)-1] = 0; } // go thru list of possible defaults: for (i = 0; fh == MUROAR_HANDLE_INVALID && addr[i] != NULL; i++) { if ( !strcmp(addr[i], MUROAR_INVALID) ) continue; fh = muroar_open_socket(addr[i]); } if ( fh == MUROAR_HANDLE_INVALID ) { _SET_ERRNO(ENOENT); return MUROAR_HANDLE_INVALID; } } // Prepare client name: if ( name == NULL || *name == 0 ) name = _DEFAULT_CLIENT_NAME; // Send IDENTIFY command to server: memset(buf, 0, sizeof(buf)); buf[1] = MUROAR_CMD_IDENTIFY; // Calculate the length for the data part of the package. // Its 5 bytes plus the length of the name string. tmpu16 = strlen(name) + 5; // check if we have space for 5 bytes + length of name + tailing \0 // in the buffer. if ( tmpu16 >= MUROAR_IOBUF ) { _CLOSE(fh); _SET_ERRNO(EINVAL); return MUROAR_HANDLE_INVALID; } buf[8] = (tmpu16 & 0xFF00) >> 8; buf[9] = (tmpu16 & 0x00FF); if ( muroar_write(fh, buf, 10) != 10 ) { _CLOSE(fh); return MUROAR_HANDLE_INVALID; } buf[0] = 1; pid = getpid(); buf[1] = (pid & 0xFF000000UL) >> 24; buf[2] = (pid & 0x00FF0000UL) >> 16; buf[3] = (pid & 0x0000FF00UL) >> 8; buf[4] = (pid & 0x000000FFUL) >> 0; // sizes are already checked. strcpy((char*)&(buf[5]), name); if ( muroar_write(fh, buf, tmpu16) != tmpu16 ) { _CLOSE(fh); return MUROAR_HANDLE_INVALID; } if ( muroar_read(fh, buf, 10) != 10 ) { _CLOSE(fh); return MUROAR_HANDLE_INVALID; } if ( buf[1] != MUROAR_CMD_OK ) { _CLOSE(fh); _SET_ERRNO(EACCES); return MUROAR_HANDLE_INVALID; } // Send AUTH command to server: // We send zero-byte AUTH command // (type=NONE). memset(buf, 0, 10); buf[1] = MUROAR_CMD_AUTH; if ( muroar_write(fh, buf, 10) != 10 ) { _CLOSE(fh); return MUROAR_HANDLE_INVALID; } if ( muroar_read(fh, buf, 10) != 10 ) { _CLOSE(fh); return MUROAR_HANDLE_INVALID; } if ( buf[1] != MUROAR_CMD_OK ) { _CLOSE(fh); _SET_ERRNO(EACCES); return MUROAR_HANDLE_INVALID; } // We now have a working control connection, return it. return fh; }
int muroar_setvolume (muroar_t fh, int stream, long unsigned int left, long unsigned int right) { unsigned char buf[20]; unsigned char ans[10]; int channels; int mode; size_t len; if ( fh == MUROAR_HANDLE_INVALID ) { _SET_ERRNO(EBADF); return -1; } if ( stream < 0 ) { _SET_ERRNO(EINVAL); return -1; } memset(buf, 0, sizeof(buf)); // header: buf[1] = MUROAR_CMD_SET_VOL; buf[2] = (stream & 0xFF00) >> 8; buf[3] = (stream & 0x00FF); // body: buf[10] = 0; // Version MSB buf[11] = 1; // Version LSB buf[12] = 0xFF; // scale MSB buf[13] = 0xFF; // scale LSB buf[14] = 0; // mode MSB for (channels = 2; channels > 0; channels--) { len = 10 + 6 + 2*channels; // total request length. buf[9] = len - 10; // body length LSB, the 10 is thhe header length for (mode = 4; mode > 0; mode -= 3) { buf[15] = mode; // mode LSB buf[16] = (left & 0xFF00) >> 8; // channel 0 MSB buf[17] = (left & 0x00FF); // channel 0 LSB buf[18] = (right & 0xFF00) >> 8; // channel 1 MSB buf[19] = (right & 0x00FF); // channel 1 LSB // send request: if ( muroar_write(fh, buf, len) != (ssize_t)len ) { return -1; } if ( muroar_read(fh, ans, 10) != 10 ) { return -1; } if ( ans[1] == MUROAR_CMD_OK ) return 0; } left = left/2 + right/2; } #ifdef ENOTSUP _SET_ERRNO(ENOTSUP); #else _SET_ERRNO(ENOSYS); #endif return -1; }