static cell_audio_handle_t audioport_init(const struct cell_audio_params *params) { init_audioport(); audioport_t *handle = calloc(1, sizeof(*handle)); CellAudioPortParam port_params = { .nChannel = params->channels, .nBlock = 8, .attr = 0 }; handle->channels = params->channels; handle->sample_cb = params->sample_cb; handle->userdata = params->userdata; handle->buffer = fifo_new(params->buffer_size ? params->buffer_size : 4096); if (params->samplerate != 48000) { handle->re = resampler_new(resampler_cb, 48000.0 / params->samplerate, params->channels, handle); } sys_lwmutex_attribute_t attr; sys_lwmutex_attribute_t attr2; sys_lwmutex_attribute_t cond_attr; sys_lwmutex_attribute_initialize(attr); sys_lwmutex_create(&handle->lock, &attr); sys_lwmutex_attribute_initialize(attr2); sys_lwmutex_create(&handle->cond_lock, &attr2); sys_lwcond_attribute_initialize(cond_attr); sys_lwcond_create(&handle->cond, &handle->cond_lock, &cond_attr); cellAudioPortOpen(&port_params, &handle->audio_port); cellAudioPortStart(handle->audio_port); pthread_create(&handle->thread, NULL, event_loop, handle); return handle; } static void audioport_pause(cell_audio_handle_t handle) { audioport_t *port = handle; port->is_paused = 1; cellAudioPortStop(port->audio_port); }
/* All and mighty connection handler. */ static void* rsd_thread(void *thread_data) { connection_t conn; void *data = NULL; wav_header_t w; wav_header_t w_orig; int resample = 0; int rc, written; void *buffer = NULL; #ifdef HAVE_SAMPLERATE SRC_STATE *resample_state = NULL; #else resampler_t *resample_state = NULL; #endif float *resample_buffer = NULL; resample_cb_state_t cb_data; connection_t *temp_conn = thread_data; conn.socket = temp_conn->socket; conn.ctl_socket = temp_conn->ctl_socket; conn.serv_ptr = 0; conn.rate_ratio = 1.0; conn.identity[0] = '\0'; free(temp_conn); if ( debug ) log_printf("Connection accepted, awaiting WAV header data ...\n"); /* Firstly, get the wave header with stream settings. */ rc = get_wav_header(conn, &w); if ( rc == -1 ) { close(conn.socket); close(conn.ctl_socket); log_printf("Couldn't read WAV header... Disconnecting.\n"); pthread_exit(NULL); } memcpy(&w_orig, &w, sizeof(wav_header_t)); if ( resample_freq > 0 && resample_freq != (int)w.sampleRate ) { w.sampleRate = resample_freq; w.bitsPerSample = w_orig.bitsPerSample == 32 ? 32 : 16; if (w_orig.bitsPerSample == 32) w.rsd_format = (is_little_endian()) ? RSD_S32_LE : RSD_S32_BE; else w.rsd_format = (is_little_endian()) ? RSD_S16_LE : RSD_S16_BE; resample = 1; conn.rate_ratio = (float)w.sampleRate * w.bitsPerSample / ((float)w_orig.sampleRate * w_orig.bitsPerSample); } if ( debug ) { log_printf("Successfully got WAV header ...\n"); pheader(&w_orig); if ( resample ) { log_printf("Resamples to:\n"); pheader(&w); } } if ( debug ) log_printf("Initializing %s ...\n", backend->backend); /* Sets up backend */ if ( backend->init(&data) < 0 ) { log_printf("Failed to initialize %s ...\n", backend->backend); goto rsd_exit; } /* Opens device with settings. */ if ( backend->open(data, &w) < 0 ) { log_printf("Failed to open audio driver ...\n"); goto rsd_exit; } backend_info_t backend_info; memset(&backend_info, 0, sizeof(backend_info)); backend->get_backend_info(data, &backend_info); if ( backend_info.chunk_size == 0 ) { log_printf("Couldn't get backend info ...\n"); goto rsd_exit; } if ( backend_info.resample ) { resample = 1; w.sampleRate = w.sampleRate * backend_info.ratio; conn.rate_ratio = backend_info.ratio; w.bitsPerSample = w_orig.bitsPerSample == 32 ? 32 : 16; if (w_orig.bitsPerSample == 32) w.rsd_format = (is_little_endian()) ? RSD_S32_LE : RSD_S32_BE; else w.rsd_format = (is_little_endian()) ? RSD_S16_LE : RSD_S16_BE; } size_t size = backend_info.chunk_size; size_t read_size = size; size_t buffer_size = (read_size > size) ? read_size : size; buffer = malloc(buffer_size); if ( buffer == NULL ) { log_printf("Could not allocate memory for buffer."); goto rsd_exit; } if ( resample ) { resample_buffer = malloc(BYTES_TO_SAMPLES(buffer_size, w.rsd_format) * sizeof(float)); if ( resample_buffer == NULL ) { log_printf("Could not allocate memory for buffer."); goto rsd_exit; } cb_data.format = w_orig.rsd_format; cb_data.data = data; cb_data.conn = &conn; cb_data.framesize = w_orig.numChannels * rsnd_format_to_bytes(w_orig.rsd_format); #ifdef HAVE_SAMPLERATE int err; resample_state = src_callback_new(resample_callback, src_converter, w.numChannels, &err, &cb_data); #else resample_state = resampler_new(resample_callback, (float)w.sampleRate/w_orig.sampleRate, w.numChannels, &cb_data); #endif if ( resample_state == NULL ) { log_printf("Could not initialize resampler."); goto rsd_exit; } } #define MAX_TCP_BUFSIZ (1 << 14) // We only bother with setting buffer size if we're doing TCP. if ( rsd_conn_type == RSD_CONN_TCP ) { int flag = 1; int bufsiz = backend_info.chunk_size * 32; if (bufsiz > MAX_TCP_BUFSIZ) bufsiz = MAX_TCP_BUFSIZ; setsockopt(conn.socket, SOL_SOCKET, SO_RCVBUF, CONST_CAST &bufsiz, sizeof(int)); if ( conn.ctl_socket ) { setsockopt(conn.ctl_socket, SOL_SOCKET, SO_RCVBUF, CONST_CAST &bufsiz, sizeof(int)); setsockopt(conn.ctl_socket, SOL_SOCKET, SO_SNDBUF, CONST_CAST &bufsiz, sizeof(int)); setsockopt(conn.ctl_socket, IPPROTO_TCP, TCP_NODELAY, CONST_CAST &flag, sizeof(int)); } setsockopt(conn.socket, IPPROTO_TCP, TCP_NODELAY, CONST_CAST &flag, sizeof(int)); } /* Now we can send backend info to client. */ if ( send_backend_info(conn, &backend_info) < 0 ) { log_printf("Failed to send backend info ...\n"); goto rsd_exit; } if ( debug ) log_printf("Initializing of %s successful ...\n", backend->backend); if ( debug ) { if ( resample ) { log_printf("Resampling active. %d Hz --> %d Hz ", (int)w_orig.sampleRate, (int)w.sampleRate); #ifdef HAVE_SAMPLERATE log_printf("(libsamplerate)\n"); #else log_printf("(internal quadratic resampler)\n"); #endif } } /* Recieve data, write to sound card. Rinse, repeat :') */ for(;;) { if ( strlen(conn.identity) > 0 && verbose ) { log_printf(" :: %s\n", conn.identity); conn.identity[0] = '\0'; } if ( resample ) { #ifdef HAVE_SAMPLERATE rc = src_callback_read(resample_state, (double)w.sampleRate/(double)w_orig.sampleRate, BYTES_TO_SAMPLES(size, w.rsd_format)/w.numChannels, resample_buffer); if (rsnd_format_to_bytes(w.rsd_format) == 4) src_float_to_int_array(resample_buffer, buffer, BYTES_TO_SAMPLES(size, w.rsd_format)); else src_float_to_short_array(resample_buffer, buffer, BYTES_TO_SAMPLES(size, w.rsd_format)); #else rc = resampler_cb_read(resample_state, BYTES_TO_SAMPLES(size, w.rsd_format)/w.numChannels, resample_buffer); if (rsnd_format_to_bytes(w.rsd_format) == 4) resampler_float_to_s32(buffer, resample_buffer, BYTES_TO_SAMPLES(size, w.rsd_format)); else resampler_float_to_s16(buffer, resample_buffer, BYTES_TO_SAMPLES(size, w.rsd_format)); #endif } else rc = receive_data(data, &conn, buffer, read_size); if ( rc <= 0 ) { if ( debug ) log_printf("Client closed connection.\n"); goto rsd_exit; } for ( written = 0; written < (int)size; ) { rc = backend->write(data, (const char*)buffer + written, size - written); if ( rc == 0 ) goto rsd_exit; written += rc; } } /* Cleanup */ rsd_exit: if ( debug ) log_printf("Closed connection.\n\n"); #ifdef _WIN32 #undef close #endif backend->close(data); #ifdef _WIN32 #define close(x) closesocket(x) #endif free(buffer); close(conn.socket); if (conn.ctl_socket) close(conn.ctl_socket); if (resample_state) { #ifdef HAVE_SAMPLERATE src_delete(resample_state); #else resampler_free(resample_state); #endif } free(resample_buffer); pthread_exit(NULL); }