void stream_close(stream_t *stream) { if (!stream) { return; } track_free(stream->track); av_free_packet(&stream->src_packet); av_free_packet(&stream->encode_packet); avcodec_free_frame(&stream->decode_frame); avcodec_free_frame(&stream->resample_frame); avcodec_free_frame(&stream->encode_frame); av_audio_fifo_free(stream->src_buf); resampler_free(&stream->resampler); if (stream->decoder) { avcodec_close(stream->decoder); } if (stream->encoder) { avcodec_close(stream->encoder); av_free(stream->encoder); } av_free(stream->dst_iobuf); av_free(stream->dst_ioctx); av_free(stream->resample_buf); av_free(stream->encode_buf); if (stream->src_ctx) { avformat_close_input(&stream->src_ctx); } if (stream->dst_ctx) { avformat_free_context(stream->dst_ctx); } free(stream); }
static void audioport_free(cell_audio_handle_t handle) { audioport_t *port = handle; port->quit_thread = 1; pthread_join(port->thread, NULL); sys_lwmutex_destroy(&port->lock); sys_lwmutex_destroy(&port->cond_lock); sys_lwcond_destroy(&port->cond); if (port->re) resampler_free(port->re); if (port->buffer) fifo_free(port->buffer); cellAudioPortStop(port->audio_port); cellAudioPortClose(port->audio_port); free(port); }
bool stream_transcode(stream_t *stream, codec_type_t codec_type, int bitrate) { int result; enum AVCodecID dst_codec_id; AVCodec *dst_codec = NULL; AVCodecContext *decoder = NULL, *encoder = NULL; enum AVSampleFormat dst_sample_fmt; int dst_sample_rate; resampler_t *resampler = NULL; if (codec_type == CODEC_TYPE_MP3) { dst_codec_id = AV_CODEC_ID_MP3; } else if (codec_type == CODEC_TYPE_OGG_VORBIS) { dst_codec_id = AV_CODEC_ID_VORBIS; } else if (codec_type == CODEC_TYPE_FLAC) { dst_codec_id = AV_CODEC_ID_FLAC; } else if (codec_type == CODEC_TYPE_AAC) { dst_codec_id = AV_CODEC_ID_AAC; } else if (codec_type == CODEC_TYPE_OPUS) { dst_codec_id = AV_CODEC_ID_OPUS; } else { musicd_log(LOG_ERROR, "stream", "unsupported encoder requested"); return false;; } dst_codec = avcodec_find_encoder(dst_codec_id); if (!dst_codec) { musicd_log(LOG_ERROR, "stream", "requested encoder not found"); return false; } decoder = stream->src_ctx->streams[0]->codec; /* Try to figure out common sample format to skip format conversion */ decoder->request_sample_fmt = find_common_sample_fmt(stream->src_codec->sample_fmts, dst_codec->sample_fmts); result = avcodec_open2(decoder, stream->src_codec, NULL); if (result < 0) { musicd_log(LOG_ERROR, "stream", "can't open decoder: %s", strerror(AVUNERROR(result))); goto fail; } dst_sample_fmt = find_sample_fmt(decoder->sample_fmt, dst_codec->sample_fmts); dst_sample_rate = find_sample_rate(decoder->sample_rate, dst_codec->supported_samplerates); /** @todo FIXME Hard-coded values. */ if (bitrate < 64000 || bitrate > 320000) { bitrate = 196000; } if (decoder->channel_layout == 0) { decoder->channel_layout = av_get_default_channel_layout(decoder->channels); } encoder = avcodec_alloc_context3(dst_codec); encoder->sample_rate = dst_sample_rate; encoder->channels = decoder->channels; encoder->sample_fmt = dst_sample_fmt; encoder->channel_layout = decoder->channel_layout; encoder->bit_rate = bitrate; result = avcodec_open2(encoder, dst_codec, NULL); if (result < 0) { musicd_log(LOG_ERROR, "stream", "can't open encoder: %s", strerror(AVUNERROR(result))); goto fail; } if (decoder->channel_layout != encoder->channel_layout || decoder->sample_fmt != encoder->sample_fmt || decoder->sample_rate != encoder->sample_rate) { resampler = resampler_alloc(); av_opt_set_int(resampler, "in_channel_layout", decoder->channel_layout, 0); av_opt_set_int(resampler, "out_channel_layout", encoder->channel_layout, 0); av_opt_set_int(resampler, "in_sample_rate", decoder->sample_rate, 0); av_opt_set_int(resampler, "out_sample_rate", encoder->sample_rate, 0); av_opt_set_int(resampler, "in_sample_fmt", decoder->sample_fmt, 0); av_opt_set_int(resampler, "out_sample_fmt", encoder->sample_fmt, 0); result = resampler_init(resampler); if (result < 0) { musicd_log(LOG_ERROR, "stream", "can't open resampler: %s", strerror(AVUNERROR(result))); goto fail; } musicd_log(LOG_DEBUG, "stream", "resample: ch:%d(%d) rate:%d fmt:%d -> ch:%d(%d) rate:%d fmt:%d", decoder->channel_layout, decoder->channels, decoder->sample_rate, decoder->sample_fmt, encoder->channel_layout, encoder->channels, encoder->sample_rate, encoder->sample_fmt); } stream->decoder = decoder; stream->encoder = encoder; stream->dst_codec = dst_codec; stream->dst_codec_type = codec_type; stream->resampler = resampler; format_from_av(encoder, &stream->format); stream->src_buf = av_audio_fifo_alloc(encoder->sample_fmt, encoder->channels, encoder->frame_size); stream->decode_frame = avcodec_alloc_frame(); if (stream->resampler) { /* The buffer will be allocated dynamically */ stream->resample_frame = avcodec_alloc_frame(); } int buf_size = av_samples_get_buffer_size(NULL, stream->encoder->channels, stream->encoder->frame_size, stream->encoder->sample_fmt, 0); stream->encode_buf = av_mallocz(buf_size); stream->encode_frame = avcodec_alloc_frame(); stream->encode_frame->nb_samples = stream->encoder->frame_size; avcodec_fill_audio_frame(stream->encode_frame, stream->encoder->channels, stream->encoder->sample_fmt, stream->encode_buf, buf_size, 0); return true; fail: if (decoder) { avcodec_close(decoder); } if (encoder) { avcodec_close(encoder); av_free(encoder); } if (resampler) { resampler_free(&resampler); } return false; }
/* 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); }