Esempio n. 1
0
void audio_trigger(context_t *context) {
  int input_fd = -1;
  static const pa_sample_spec ss = {
    .format = PA_SAMPLE_S16LE,
    .rate = 44100,
    .channels = 1
  };
  int error;

  daemon_log(LOG_INFO, "Trigger %s", context->shush_filename);

  if (context->points_threshold < 0) {
    daemon_log(LOG_INFO, "Threshold below 0, not triggering sound");
  }

  daemon_log(LOG_INFO,
             "Opening %s for output",
             context->output_device ?: "default sink");

  pa_simple *pa_output = pa_simple_new(
                              NULL,
                              "shusherd",
                              PA_STREAM_PLAYBACK,
                              context->output_device,
                              "playback",
                              &ss,
                              NULL,
                              NULL,
                              &error);
  if (!pa_output) {
    daemon_log(LOG_ERR, "pa_simple_new failed: %s", pa_strerror(error));
    goto finish;
  }

  input_fd = open(context->shush_filename, O_RDONLY);
  if (input_fd < 0) {
    daemon_log(LOG_ERR, "Error reading %s: %s", context->shush_filename, strerror(errno));
    goto finish;
  }

  for (;;) {
    uint8_t buf[BUFSIZE];
    ssize_t r;

    r = read(input_fd, buf, sizeof(buf));
    if (r < 0) {
      daemon_log(LOG_ERR, "read() failed: %s", strerror(errno));
      goto finish;
    }

    if (r == 0)
      goto finish;

    if (pa_simple_write(pa_output, buf, (size_t) r, &error) < 0) {
      daemon_log(LOG_ERR, "pa_simple_write() failed: %s", pa_strerror(errno));
      goto finish;
    }
  }

  if (pa_simple_drain(pa_output, &error) < 0) {
    daemon_log(LOG_ERR, "pa_simple_drain() failed: %s", pa_strerror(errno));
    goto finish;
  }

finish:
  if (input_fd > 0)
    close(input_fd);
  if (pa_output)
    pa_simple_free(pa_output);
}

void *audio_loop(void *context_p) {
  context_t *context = (context_t *)context_p;
  time_t t = time(NULL);
  double loudness;
  double points = 0.0;
  int error;

  //pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

  daemon_log(LOG_INFO, "Starting listening...");

  const short buf[BUFSIZE/2];

  int bytes = 0;
  int trigger = 0;
  int latest_trigger_time = 0;

  while (context->enable_processing) {
    if ((bytes = pa_simple_read(context->pa_input, (void *)buf, sizeof(buf), &error)) < 0) {
      daemon_log(LOG_ERR, "pa_simple_read failed: %s", pa_strerror(error));
      assert(0);
    }

    if ((time(NULL) - latest_trigger_time) < context->cooldown) {
      continue;
    }

    ebur128_add_frames_short(context->ebur128_state, buf, sizeof(buf)/2);

    if ((time(NULL) - t) > SAMPLE_TIME) {
      t = time(NULL);
      ebur128_loudness_shortterm(context->ebur128_state, &loudness);

      points += 100 - fabs(loudness);

      daemon_log(LOG_INFO, "Points: %f (%d) (%f)",
                 points, context->points_threshold, loudness);

      if (points > context->points_threshold) {
        trigger = 1;
      } else {
        points *= context->decay;
      }
    }

    if (trigger) {
      latest_trigger_time = time(NULL);
      audio_trigger(context);
      points = 0;
      trigger = 0;
      daemon_log(LOG_INFO,
                 "Waiting %d seconds before listening again",
                 context->cooldown);
    }
  }

  daemon_log(LOG_INFO, "Stopped listening...");

  return 0;
}
Esempio n. 2
0
static void analyze_audio( mlt_filter filter, void* buffer, int samples )
{
	mlt_properties properties = MLT_FILTER_PROPERTIES( filter );
	private_data* pdata = (private_data*)filter->child;
	int result = -1;
	double loudness = 0.0;

	ebur128_add_frames_float( pdata->r128, buffer, samples );

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_program" ) )
	{
		result = ebur128_loudness_global( pdata->r128, &loudness );
		if( result == EBUR128_SUCCESS && loudness != HUGE_VAL && loudness != -HUGE_VAL )
		{
			mlt_properties_set_double( properties, "program", loudness );
		}
	}

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_shortterm" ) )
	{
		result = ebur128_loudness_shortterm( pdata->r128, &loudness );
		if( result == EBUR128_SUCCESS && loudness != HUGE_VAL && loudness != -HUGE_VAL )
		{
			mlt_properties_set_double( properties, "shortterm", loudness );
		}
	}

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_momentary" ) )
	{
		result = ebur128_loudness_momentary( pdata->r128, &loudness );
		if( result == EBUR128_SUCCESS && loudness != HUGE_VAL && loudness != -HUGE_VAL )
		{
			mlt_properties_set_double( properties, "momentary", loudness );
		}
	}

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_range" ) )
	{
		double range = 0;
		result = ebur128_loudness_range( pdata->r128, &range );
		if( result == EBUR128_SUCCESS && range != HUGE_VAL && range != -HUGE_VAL )
		{
			mlt_properties_set_double( properties, "range", range );
		}
	}

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_peak" ) )
	{
		double prev_peak = 0.0;
		double max_peak = 0.0;
		int c = 0;
		for( c = 0; c < pdata->r128->channels; c++ )
		{
			double peak;
			result = ebur128_sample_peak( pdata->r128, c, &peak );
			if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > max_peak )
			{
				max_peak = peak;
			}
			result = ebur128_prev_sample_peak( pdata->r128, c, &peak );
			if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > prev_peak )
			{
				prev_peak = peak;
			}
		}
		mlt_properties_set_double( properties, "max_peak", 20 * log10(max_peak) );
		mlt_properties_set_double( properties, "peak", 20 * log10(prev_peak) );
	}

	if( mlt_properties_get_int( MLT_FILTER_PROPERTIES(filter), "calc_true_peak" ) )
	{
		double prev_peak = 0.0;
		double max_peak = 0.0;
		int c = 0;
		for( c = 0; c < pdata->r128->channels; c++ )
		{
			double peak;
			result = ebur128_true_peak( pdata->r128, c, &peak );
			if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > max_peak )
			{
				max_peak = peak;
			}
			result = ebur128_prev_true_peak( pdata->r128, c, &peak );
			if( result == EBUR128_SUCCESS && peak != HUGE_VAL && peak > prev_peak )
			{
				prev_peak = peak;
			}
		}
		mlt_properties_set_double( properties, "max_true_peak", 20 * log10(max_peak) );
		mlt_properties_set_double( properties, "true_peak", 20 * log10(prev_peak) );
	}

	mlt_properties_set_position( properties, "frames_processed", mlt_properties_get_position( properties, "frames_processed" ) + 1 );
}
int main(int argc, const char *argv[])
{
  struct sockaddr_in addr, graphiteAddr;
  int addrlen, sock, packetLength, graphiteSocket;
  struct ip_mreq mreq;
  uint8_t packet[1452]; 
  //uint16_t sequenceNumber;
  //uint32_t timestamp;
  double audioPayload[480]; 
  ebur128_state* state = NULL;
  double shortTermLoudness;
  uint32_t frameCounter = 0;
  char graphiteOutputBuffer[200];

  if (argc != 4) {
    fprintf(stderr, "Argument Error!\n");
    fprintf(stderr, "Correct usage: axialufsgraphite <MC Livewire IP> <Graphite Server IP> <Graphite Metric>\n");
    fprintf(stderr, "Example: axialufsgraphite 239.192.2.169 127.0.0.1 Studio442PGM\n");
    return 1;
  }

  const char *axiaLivewireIP = argv[1];
  const char *graphiteServerIP = argv[2];
  const char *graphiteMetric = argv[3];

  /* setup graphite socket */
  graphiteSocket = socket(AF_INET,SOCK_STREAM,0);
  memset(&graphiteAddr, 0, sizeof(graphiteAddr));
  graphiteAddr.sin_family = AF_INET;
  graphiteAddr.sin_port = htons(2003);
  inet_pton(AF_INET, graphiteServerIP, &(graphiteAddr.sin_addr));
  connect(graphiteSocket,(struct sockaddr *) &graphiteAddr, sizeof(graphiteAddr));
 
  /* setup axia socket (multicast UDP listener) */
  sock = socket(AF_INET, SOCK_DGRAM, 0);
  int reuse = 1;
  if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) {
      fprintf(stderr, "setsockopt: %d\n", errno);
      return 1;
  }
  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = htons(5004);
  addr.sin_addr.s_addr = inet_addr(axiaLivewireIP);
  addrlen = sizeof(addr);
  if (bind(sock, (struct sockaddr*) &addr, sizeof(addr)) == -1) {
      fprintf(stderr, "bind: %d\n", errno);
      return 1;
  }
  mreq.imr_multiaddr.s_addr = inet_addr(axiaLivewireIP);         
  mreq.imr_interface.s_addr = htonl(INADDR_ANY);
  setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));

  /* init ebur128 state */
  state = malloc((size_t) sizeof(ebur128_state*));
  state = ebur128_init((unsigned) 2, (unsigned) 48000, EBUR128_MODE_S);

  /* main loop */
  while(1){
    packetLength = recvfrom(sock, packet, sizeof(packet), 0, (struct sockaddr *) &addr, (socklen_t *) &addrlen);
    
    //sequenceNumber = (packet[2] << 8 | packet[3]);
    //timestamp = (packet[4] << 24 | packet[5] << 16 | packet[6] << 8 | packet[7]);

    for (int i = 12; i < packetLength; i += 3) {
      int32_t audioPCM = ((packet[i] << 16) | (packet[i + 1] << 8) | (packet[i + 2]));
      if (audioPCM & 0x800000) audioPCM |= ~0xffffff; // Convert to signed PCM.
      double audioFloat = (audioPCM * (1.0 / 0x7fffff)); // Convert to float.
      audioPayload[((i - 12) / 3)] = audioFloat;
    }

    ebur128_add_frames_double(state, audioPayload, (size_t) ((packetLength - 12) / 6));

    frameCounter += ((packetLength - 12) / 6);
    if (frameCounter >= 47999) {
      frameCounter = 0;
      ebur128_loudness_shortterm(state, &shortTermLoudness);
      shortTermLoudness = shortTermLoudness <= -70. ? -70. : shortTermLoudness;
      sprintf(graphiteOutputBuffer, "%s %f %d\n", graphiteMetric, shortTermLoudness, (int) time(NULL)); 
      send(graphiteSocket, graphiteOutputBuffer, (strlen(graphiteOutputBuffer)), 0);
    } 
  }
  free(state);
  return 0;
}