Ejemplo n.º 1
0
Archivo: stream.c Proyecto: EQ4/musicd
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);
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
Archivo: stream.c Proyecto: EQ4/musicd
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;
}
Ejemplo n.º 4
0
/* 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);
}