Beispiel #1
0
APULSE_EXPORT
size_t
pa_frame_size(const pa_sample_spec *spec)
{
    return spec->channels * pa_sample_size(spec);
}
static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *memchunk) {
    struct userdata *u = PA_SINK(o)->userdata;

    switch (code) {

        case SINK_MESSAGE_RENDER:

            /* Handle the request from the JACK thread */

            if (u->sink->thread_info.state == PA_SINK_RUNNING) {
                pa_memchunk chunk;
                size_t nbytes;
                void *p;

                pa_assert(offset > 0);
                nbytes = (size_t) offset * pa_frame_size(&u->sink->sample_spec);

                pa_sink_render_full(u->sink, nbytes, &chunk);

                p = (uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index;
                pa_deinterleave(p, u->buffer, u->channels, sizeof(float), (unsigned) offset);
                pa_memblock_release(chunk.memblock);

                pa_memblock_unref(chunk.memblock);
            } else {
                unsigned c;
                pa_sample_spec ss;

                /* Humm, we're not RUNNING, hence let's write some silence */

                ss = u->sink->sample_spec;
                ss.channels = 1;

                for (c = 0; c < u->channels; c++)
                    pa_silence_memory(u->buffer[c], (size_t) offset * pa_sample_size(&ss), &ss);
            }

            u->frames_in_buffer = (jack_nframes_t) offset;
            u->saved_frame_time = * (jack_nframes_t*) data;
            u->saved_frame_time_valid = TRUE;

            return 0;

        case SINK_MESSAGE_BUFFER_SIZE:
            pa_sink_set_max_request_within_thread(u->sink, (size_t) offset * pa_frame_size(&u->sink->sample_spec));
            return 0;

        case SINK_MESSAGE_ON_SHUTDOWN:
            pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
            return 0;

        case PA_SINK_MESSAGE_GET_LATENCY: {
            jack_nframes_t l, ft, d;
            size_t n;

            /* This is the "worst-case" latency */
            l = jack_port_get_total_latency(u->client, u->port[0]) + u->frames_in_buffer;

            if (u->saved_frame_time_valid) {
                /* Adjust the worst case latency by the time that
                 * passed since we last handed data to JACK */

                ft = jack_frame_time(u->client);
                d = ft > u->saved_frame_time ? ft - u->saved_frame_time : 0;
                l = l > d ? l - d : 0;
            }

            /* Convert it to usec */
            n = l * pa_frame_size(&u->sink->sample_spec);
            *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec);

            return 0;
        }

    }

    return pa_sink_process_msg(o, code, data, offset, memchunk);
}
Beispiel #3
0
static void *
audio_capture_thr(void *args)
{
	int error;
	PSAUDIORECTHRPARAMS params = (PSAUDIORECTHRPARAMS)args;
	pa_simple *pa_context = NULL;
	uint8_t active = 1;
	uint32_t buffer_size;

	SSAMPLEHEADER  sample_header = {0};
	HBUF sample;

	TIMING_MEASURE_AREA;

	buffer_size = HEADER_SIZE + params->sample_spec->channels *
					params->buffer_size * pa_sample_size(params->sample_spec);

	sample_header.number = 0;
	sample_header.buf_type = BUF_TYPE_INTERLEAVED;
	sample_header.sample_size = pa_sample_size(params->sample_spec);
	sample_header.samples = params->buffer_size;
	sample_header.channels = params->sample_spec->channels;
	sample_header.samplerate = params->sample_spec->rate;

	if ( !(pa_context = pa_simple_new(NULL, params->argv[0],
			PA_STREAM_RECORD, NULL, "record",
			params->sample_spec, NULL, NULL, &error)) ) {
		fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
		goto audio_thr_finish;
	}

	printf("[source] audio thr\n");

	while (active) {
		TIMING_START();

		sample = buf_alloc(NULL);
		buf_resize(sample, buffer_size);
		sample->full_size = sample->size = sample->alloced_size;
		sample_zero_buffer(sample);
		memcpy(sample->buf, &sample_header, sizeof(SSAMPLEHEADER));

        if (pa_simple_read(pa_context, sample->buf + HEADER_SIZE,
						sample->alloced_size - HEADER_SIZE, &error) < 0) {
            fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error));
            goto audio_thr_finish;
        }
		pa_gettimeofday(&(sample_header.timestamp));
		sample_header.number += 1;

		/* printf("[audio] read %p\n", sample); */

		if ( (error = write(params->pipefd, &sample, sizeof(sample))) != sizeof(sample)) {
			if (error == -1) {
				handle_error("[audio] write()");
			}

			buf_free(sample);
			perror("[audio] ");
			printf("[audio] uverrun. free buffer\n");
		}

		active = params->active;

		TIMING_END(" audio");
	}

audio_thr_finish:

	pa_simple_free(pa_context);

	return NULL;
}
static void audio_callback(void* data)
{
  sa_stream_t* s = (sa_stream_t*)data;
  unsigned int bytes_per_frame = s->sample_spec.channels * pa_sample_size(&s->sample_spec);
  size_t buffer_size = s->sample_spec.rate * bytes_per_frame;
  char* buffer = malloc(buffer_size);

  while(1) {
    char* dst = buffer;
    size_t bytes_to_copy, bytes;

    pa_threaded_mainloop_lock(s->m);
    while(1) {
      if (s == NULL || s->stream == NULL) {
        if (s != NULL && s->m != NULL) 
          pa_threaded_mainloop_unlock(s->m);
        goto free_buffer;
      }
      if ((bytes_to_copy = pa_stream_writable_size(s->stream)) == (size_t) -1) {
        fprintf(stderr, "pa_stream_writable_size() failed: %s", pa_strerror(pa_context_errno(s->context)));
        pa_threaded_mainloop_unlock(s->m);
        goto free_buffer;
      }
      if(bytes_to_copy > 0)
        break;
      pa_threaded_mainloop_wait(s->m);
    }
    pa_threaded_mainloop_unlock(s->m);
    if (bytes_to_copy > buffer_size)
      bytes_to_copy = buffer_size;
    bytes = bytes_to_copy;

    pthread_mutex_lock(&s->mutex);
    if (!s->thread_id) {
      pthread_mutex_unlock(&s->mutex);
      break;
    }
    /*
     * Consume data from the start of the buffer list.
     */
    while (1) {
      unsigned int avail = s->bl_head->end - s->bl_head->start;
      assert(s->bl_head->start <= s->bl_head->end);

      if (avail >= bytes_to_copy) {
        /*
         * We have all we need in the head buffer, so just grab it and go.
         */
        memcpy(dst, s->bl_head->data + s->bl_head->start, bytes_to_copy);
        s->bl_head->start += bytes_to_copy;
        break;
    
      } else {
        sa_buf* next = 0;
        /*
         * Copy what we can from the head and move on to the next buffer.
         */
        memcpy(dst, s->bl_head->data + s->bl_head->start, avail);
        s->bl_head->start += avail;
        dst += avail;
        bytes_to_copy -= avail;
        /*
         * We want to free the now-empty buffer, but not if it's also the
         * current tail. If it is the tail, we don't have enough data to fill
         * the destination buffer, so we write less and give up.
         */
        next = s->bl_head->next;
        if (next == NULL) {
          bytes = bytes-bytes_to_copy;
          break;
        }
        free(s->bl_head);
        s->bl_head = next;
        s->n_bufs--;
      } /* if (avail >= bytes_to_copy), else */
    } /* while (1) */

    if(bytes > 0) {
      pa_threaded_mainloop_lock(s->m);
      if (pa_stream_write(s->stream, buffer, bytes, NULL, 0, PA_SEEK_RELATIVE) < 0) {
        fprintf(stderr, "pa_stream_write() failed: %s", pa_strerror(pa_context_errno(s->context)));
        pa_threaded_mainloop_unlock(s->m);
        return;
      }
      pa_stream_update_timing_info(s->stream, NULL, NULL);
      s->bytes_written += bytes;
      pa_threaded_mainloop_unlock(s->m);
    }
    pthread_mutex_unlock(&s->mutex);
  }
free_buffer:
  free(buffer);
}
Beispiel #5
0
/** Return the size of a frame with the specific sample type */
size_t pa_frame_size(const pa_sample_spec *spec) {
 if ( spec == NULL )
  return 0;

 return pa_sample_size(spec) * spec->channels;
}