Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for JS to configure ring-buffer size. #37

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions deps/mpg123/src/audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ typedef struct audio_output_struct
long gain; /* output gain */
int channels; /* number of channels */
int format; /* format flags */
int bufferSize; /* Size of each audio buffer to keep ahead */
int numBuffers; /* Number of audio buffers to keep ahead */
int is_open; /* something opened? */
#define MPG123_OUT_QUIET 1
int auxflags; /* For now just one: quiet mode (for probing). */
Expand Down
45 changes: 23 additions & 22 deletions deps/mpg123/src/output/win32.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,10 @@
#include <windows.h>
#include "debug.h"

/*
Buffer size and number of buffers in the playback ring
NOTE: This particular num/size combination performs best under heavy
loads for my system, however this may not be true for any hardware/OS out there.
Generally, BUFFER_SIZE < 8k || NUM_BUFFERS > 16 || NUM_BUFFERS < 4 are not recommended.
*/
#define BUFFER_SIZE 0x10000
#define NUM_BUFFERS 8 /* total 512k roughly 2.5 sec of CD quality sound */

/* Buffer ring queue state */
struct queue_state
{
WAVEHDR buffer_headers[NUM_BUFFERS];
WAVEHDR* buffer_headers;
/* The next buffer to be filled and put in playback */
int next_buffer;
/* Buffer playback completion event */
Expand All @@ -46,12 +37,21 @@ static int open_win32(struct audio_output_struct *ao)
/* Allocate queue state struct for this device */
state = calloc(1, sizeof(struct queue_state));
if(!state) return -1;


state->buffer_headers = calloc(ao->numBuffers, sizeof(WAVEHDR));
if (!state->buffer_headers) {
free(state);
return -1;
}

ao->userptr = state;
/* Allocate playback buffers */
for(i = 0; i < NUM_BUFFERS; i++)
if(!(state->buffer_headers[i].lpData = malloc(BUFFER_SIZE)))
ereturn(-1, "Out of memory for playback buffers.");
for(i = 0; i < ao->numBuffers; i++) {
if(!(state->buffer_headers[i].lpData = malloc(ao->bufferSize))) {
ereturn(-1, "Out of memory for playback buffers.");
}
state->buffer_headers[i].dwFlags = WHDR_DONE;
}

state->play_done_event = CreateEvent(0,FALSE,FALSE,0);
if(state->play_done_event == INVALID_HANDLE_VALUE) return -1;
Expand Down Expand Up @@ -118,7 +118,7 @@ static int write_win32(struct audio_output_struct *ao, unsigned char *buf, int l

/* Check buffer header and wait if it's being played.
Skip waiting if the buffer is not full yet */
while(hdr->dwBufferLength == BUFFER_SIZE && !(hdr->dwFlags & WHDR_DONE))
while(hdr->dwBufferLength == ao->bufferSize && !(hdr->dwFlags & WHDR_DONE))
{
/* debug1("waiting for buffer %i...", state->next_buffer); */
WaitForSingleObject(state->play_done_event, INFINITE);
Expand All @@ -133,13 +133,13 @@ static int write_win32(struct audio_output_struct *ao, unsigned char *buf, int l
}

/* Now see how much we want to stuff in and then stuff it in. */
bufill = BUFFER_SIZE - hdr->dwBufferLength;
bufill = ao->bufferSize - hdr->dwBufferLength;
if(len < bufill) bufill = len;

rest_len = len - bufill;
memcpy(hdr->lpData + hdr->dwBufferLength, buf, bufill);
hdr->dwBufferLength += bufill;
if(hdr->dwBufferLength == BUFFER_SIZE)
if(hdr->dwBufferLength == ao->bufferSize)
{ /* Send the buffer out when it's full. */
res = waveOutPrepareHeader(state->waveout, hdr, sizeof(WAVEHDR));
if(res != MMSYSERR_NOERROR) ereturn(-1, "Can't write to audio output device (prepare).");
Expand All @@ -148,7 +148,7 @@ static int write_win32(struct audio_output_struct *ao, unsigned char *buf, int l
if(res != MMSYSERR_NOERROR) ereturn(-1, "Can't write to audio output device.");

/* Cycle to the next buffer in the ring queue */
state->next_buffer = (state->next_buffer + 1) % NUM_BUFFERS;
state->next_buffer = (state->next_buffer + 1) % ao->numBuffers;
}
/* I'd like to propagate error codes or something... but there are no catchable surprises left.
Anyhow: Here is the recursion that makes ravenexp happy;-) */
Expand All @@ -169,15 +169,15 @@ static void flush_win32(struct audio_output_struct *ao)
/* FIXME: The very last output buffer is not played. This could be a problem on the feeding side. */
i = 0;
z = state->next_buffer - 1;
for(i = 0; i < NUM_BUFFERS; i++)
for(i = 0; i < ao->numBuffers; i++)
{
if(!state->buffer_headers[i].dwFlags & WHDR_DONE)
WaitForSingleObject(state->play_done_event, INFINITE);

waveOutUnprepareHeader(state->waveout, &state->buffer_headers[i], sizeof(WAVEHDR));
state->buffer_headers[i].dwFlags = 0;
state->buffer_headers[i].dwBufferLength = 0;
z = (z + 1) % NUM_BUFFERS;
z = (z + 1) % ao->numBuffers;
}
}

Expand All @@ -193,8 +193,9 @@ static int close_win32(struct audio_output_struct *ao)
waveOutClose(state->waveout);
CloseHandle(state->play_done_event);

for(i = 0; i < NUM_BUFFERS; i++) free(state->buffer_headers[i].lpData);

for(i = 0; i < ao->numBuffers; i++) free(state->buffer_headers[i].lpData);
free(state->buffer_headers);

free(ao->userptr);
ao->userptr = 0;
return 0;
Expand Down
19 changes: 18 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,15 @@ Speaker.prototype._open = function () {
debug('setting default %o: %o', 'signed', this.bitDepth != 8);
this.signed = this.bitDepth != 8;
}
if (null == this.bufferSize) {
debug('setting defualt %o: %o', 'bufferSize', 0x10000);
this.bufferSize = 0x10000;
}

if (null == this.numBuffers) {
debug('setting default %o: %o', 'numBuffers', 8);
this.numBuffers = 8;
}

var format = exports.getFormat(this);
if (null == format) {
Expand All @@ -163,7 +172,7 @@ Speaker.prototype._open = function () {
// initialize the audio handle
// TODO: open async?
this.audio_handle = new Buffer(binding.sizeof_audio_output_t);
var r = binding.open(this.audio_handle, this.channels, this.sampleRate, format);
var r = binding.open(this.audio_handle, this.channels, this.sampleRate, format, this.bufferSize, this.numBuffers);
if (0 !== r) {
throw new Error('open() failed: ' + r);
}
Expand Down Expand Up @@ -203,6 +212,14 @@ Speaker.prototype._format = function (opts) {
debug('setting %o: %o', "signed", opts.signed);
this.signed = opts.signed;
}
if (null != opts.bufferSize) {
debug('setting %o: %o', "bufferSize", opts.bufferSize);
this.bufferSize = opts.bufferSize;
}
if (null != opts.numBuffers) {
debug('setting %o: %o', "numBuffers", opts.numBuffers);
this.numBuffers = opts.numBuffers;
}
if (null != opts.samplesPerFrame) {
debug('setting %o: %o', "samplesPerFrame", opts.samplesPerFrame);
this.samplesPerFrame = opts.samplesPerFrame;
Expand Down
4 changes: 4 additions & 0 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ NAN_METHOD(Open) {
ao->channels = args[1]->Int32Value(); /* channels */
ao->rate = args[2]->Int32Value(); /* sample rate */
ao->format = args[3]->Int32Value(); /* MPG123_ENC_* format */
ao->bufferSize = args[4]->Int32Value();
ao->numBuffers = args[5]->Int32Value();

/* init_output() */
r = mpg123_output_module_info.init_output(ao);
Expand Down Expand Up @@ -118,6 +120,8 @@ void Initialize(Handle<Object> target) {
ao.channels = 2;
ao.rate = 44100;
ao.format = MPG123_ENC_SIGNED_16;
ao.numBuffers = 8;
ao.bufferSize = 0x10000;
ao.open(&ao);
target->Set(NanNew<v8::String>("formats"), NanNew<v8::Integer>(ao.get_formats(&ao)));
ao.close(&ao);
Expand Down