Esempio n. 1
0
static const struct audio_format *
route_filter_open(struct filter *_filter, struct audio_format *audio_format,
		  G_GNUC_UNUSED GError **error_r)
{
	struct route_filter *filter = (struct route_filter *)_filter;

	// Copy the input format for later reference
	filter->input_format = *audio_format;
	filter->input_frame_size =
		audio_format_frame_size(&filter->input_format);

	// Decide on an output format which has enough channels,
	// and is otherwise identical
	filter->output_format = *audio_format;
	filter->output_format.channels = filter->min_output_channels;

	// Precalculate this simple value, to speed up allocation later
	filter->output_frame_size =
		audio_format_frame_size(&filter->output_format);

	// This buffer grows as needed
	pcm_buffer_init(&filter->output_buffer);

	return &filter->output_format;
}
/**
 * Sends a chunk of silence to the audio outputs.  This is called when
 * there is not enough decoded data in the pipe yet, to prevent
 * underruns in the hardware buffers.
 *
 * The player lock is not held.
 */
static bool
player_send_silence(struct player *player)
{
	assert(audio_format_defined(&player->play_audio_format));

	struct music_chunk *chunk = music_buffer_allocate(player_buffer);
	if (chunk == NULL) {
		g_warning("Failed to allocate silence buffer");
		return false;
	}

#ifndef NDEBUG
	chunk->audio_format = player->play_audio_format;
#endif

	size_t frame_size =
		audio_format_frame_size(&player->play_audio_format);
	/* this formula ensures that we don't send
	   partial frames */
	unsigned num_frames = sizeof(chunk->data) / frame_size;

	chunk->times = -1.0; /* undefined time stamp */
	chunk->length = num_frames * frame_size;
	memset(chunk->data, 0, chunk->length);

	if (!audio_output_all_play(chunk)) {
		music_buffer_return(player_buffer, chunk);
		return false;
	}

	return true;
}
Esempio n. 3
0
/**
 * This function attempts to call decoder_initialized() in case there
 * was no STREAMINFO block.  This is allowed for nonseekable streams,
 * where the server sends us only a part of the file, without
 * providing the STREAMINFO block from the beginning of the file
 * (e.g. when seeking with SqueezeBox Server).
 */
static bool
flac_got_first_frame(struct flac_data *data, const FLAC__FrameHeader *header)
{
	if (data->unsupported)
		return false;

	GError *error = NULL;
	if (!audio_format_init_checked(&data->audio_format,
				       header->sample_rate,
				       flac_sample_format(header->bits_per_sample),
				       header->channels, &error)) {
		g_warning("%s", error->message);
		g_error_free(error);
		data->unsupported = true;
		return false;
	}

	data->frame_size = audio_format_frame_size(&data->audio_format);

	decoder_initialized(data->decoder, &data->audio_format,
			    data->input_stream->seekable,
			    (float)data->total_frames /
			    (float)data->audio_format.sample_rate);

	data->initialized = true;

	return true;
}
Esempio n. 4
0
static void
flac_got_stream_info(struct flac_data *data,
		     const FLAC__StreamMetadata_StreamInfo *stream_info)
{
	if (data->initialized || data->unsupported)
		return;

	GError *error = NULL;
	if (!audio_format_init_checked(&data->audio_format,
				       stream_info->sample_rate,
				       flac_sample_format(stream_info->bits_per_sample),
				       stream_info->channels, &error)) {
		g_warning("%s", error->message);
		g_error_free(error);
		data->unsupported = true;
		return;
	}

	data->frame_size = audio_format_frame_size(&data->audio_format);

	if (data->total_frames == 0)
		data->total_frames = stream_info->total_samples;

	data->initialized = true;
}
Esempio n. 5
0
static bool
twolame_encoder_write(struct encoder *_encoder,
		      const void *data, size_t length,
		      G_GNUC_UNUSED GError **error)
{
	struct twolame_encoder *encoder = (struct twolame_encoder *)_encoder;
	unsigned num_frames;
	const int16_t *src = (const int16_t*)data;
	int bytes_out;

	assert(encoder->buffer_length == 0);

	num_frames =
		length / audio_format_frame_size(&encoder->audio_format);

	bytes_out = twolame_encode_buffer_interleaved(encoder->options,
						      src, num_frames,
						      encoder->buffer,
						      sizeof(encoder->buffer));
	if (bytes_out < 0) {
		g_set_error(error, twolame_encoder_quark(), 0,
			    "twolame encoder failed");
		return false;
	}

	encoder->buffer_length = (size_t)bytes_out;
	return true;
}
static void
sndfile_stream_decode(struct decoder *decoder, struct input_stream *is)
{
	GError *error = NULL;
	SNDFILE *sf;
	SF_INFO info;
	struct audio_format audio_format;
	size_t frame_size;
	sf_count_t read_frames, num_frames;
	int buffer[4096];
	enum decoder_command cmd;

	info.format = 0;

	sf = sf_open_virtual(&vio, SFM_READ, &info, is);
	if (sf == NULL) {
		g_warning("sf_open_virtual() failed");
		return;
	}

	/* for now, always read 32 bit samples.  Later, we could lower
	   MPD's CPU usage by reading 16 bit samples with
	   sf_readf_short() on low-quality source files. */
	if (!audio_format_init_checked(&audio_format, info.samplerate,
				       SAMPLE_FORMAT_S32,
				       info.channels, &error)) {
		g_warning("%s", error->message);
		g_error_free(error);
		return;
	}

	decoder_initialized(decoder, &audio_format, info.seekable,
			    frame_to_time(info.frames, &audio_format));

	frame_size = audio_format_frame_size(&audio_format);
	read_frames = sizeof(buffer) / frame_size;

	do {
		num_frames = sf_readf_int(sf, buffer, read_frames);
		if (num_frames <= 0)
			break;

		cmd = decoder_data(decoder, is,
				   buffer, num_frames * frame_size,
				   0);
		if (cmd == DECODE_COMMAND_SEEK) {
			sf_count_t c =
				time_to_frame(decoder_seek_where(decoder),
					      &audio_format);
			c = sf_seek(sf, c, SEEK_SET);
			if (c < 0)
				decoder_seek_error(decoder);
			else
				decoder_command_finished(decoder);
			cmd = DECODE_COMMAND_NONE;
		}
	} while (cmd == DECODE_COMMAND_NONE);

	sf_close(sf);
}
Esempio n. 7
0
static bool
ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk)
{
    GError *error = NULL;

    assert(ao != NULL);
    assert(ao->filter != NULL);

    if (chunk->tag != NULL) {
        g_mutex_unlock(ao->mutex);
        ao_plugin_send_tag(ao->plugin, ao->data, chunk->tag);
        g_mutex_lock(ao->mutex);
    }

    size_t size;
    const char *data = ao_filter_chunk(ao, chunk, &size);
    if (data == NULL) {
        ao_close(ao, false);

        /* don't automatically reopen this device for 10
           seconds */
        ao->fail_timer = g_timer_new();
        return false;
    }

    while (size > 0 && ao->command == AO_COMMAND_NONE) {
        size_t nbytes;

        if (!ao_wait(ao))
            break;

        g_mutex_unlock(ao->mutex);
        nbytes = ao_plugin_play(ao->plugin, ao->data, data, size,
                                &error);
        g_mutex_lock(ao->mutex);
        if (nbytes == 0) {
            /* play()==0 means failure */
            g_warning("\"%s\" [%s] failed to play: %s",
                      ao->name, ao->plugin->name, error->message);
            g_error_free(error);

            ao_close(ao, false);

            /* don't automatically reopen this device for
               10 seconds */
            assert(ao->fail_timer == NULL);
            ao->fail_timer = g_timer_new();

            return false;
        }

        assert(nbytes <= size);
        assert(nbytes % audio_format_frame_size(&ao->out_audio_format) == 0);

        data += nbytes;
        size -= nbytes;
    }

    return true;
}
Esempio n. 8
0
static bool
winmm_output_open(void *data, struct audio_format *audio_format,
		  GError **error_r)
{
	struct winmm_output *wo = data;

	wo->event = CreateEvent(NULL, false, false, NULL);
	if (wo->event == NULL) {
		g_set_error(error_r, winmm_output_quark(), 0,
			    "CreateEvent() failed");
		return false;
	}

	switch (audio_format->format) {
	case SAMPLE_FORMAT_S8:
	case SAMPLE_FORMAT_S16:
		break;

	case SAMPLE_FORMAT_S24:
	case SAMPLE_FORMAT_S24_P32:
	case SAMPLE_FORMAT_S32:
	case SAMPLE_FORMAT_UNDEFINED:
		/* we havn't tested formats other than S16 */
		audio_format->format = SAMPLE_FORMAT_S16;
		break;
	}

	if (audio_format->channels > 2)
		/* same here: more than stereo was not tested */
		audio_format->channels = 2;

	WAVEFORMATEX format;
	format.wFormatTag = WAVE_FORMAT_PCM;
	format.nChannels = audio_format->channels;
	format.nSamplesPerSec = audio_format->sample_rate;
	format.nBlockAlign = audio_format_frame_size(audio_format);
	format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
	format.wBitsPerSample = audio_format_sample_size(audio_format) * 8;
	format.cbSize = 0;

	MMRESULT result = waveOutOpen(&wo->handle, wo->device_id, &format,
				      (DWORD_PTR)wo->event, 0, CALLBACK_EVENT);
	if (result != MMSYSERR_NOERROR) {
		CloseHandle(wo->event);
		g_set_error(error_r, winmm_output_quark(), result,
			    "waveOutOpen() failed");
		return false;
	}

	for (unsigned i = 0; i < G_N_ELEMENTS(wo->buffers); ++i) {
		pcm_buffer_init(&wo->buffers[i].buffer);
		memset(&wo->buffers[i].hdr, 0, sizeof(wo->buffers[i].hdr));
	}

	wo->next_buffer = 0;

	return true;
}
Esempio n. 9
0
Timer *timer_new(const struct audio_format *af)
{
	Timer *timer = g_new(Timer, 1);
	timer->time = 0;
	timer->started = 0;
	timer->rate = af->sample_rate * audio_format_frame_size(af);

	return timer;
}
Esempio n. 10
0
static bool
flac_encoder_write(struct encoder *_encoder,
		      const void *data, size_t length,
		      G_GNUC_UNUSED GError **error)
{
	struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
	unsigned num_frames, num_samples;
	void *exbuffer;
	const void *buffer = NULL;

	/* format conversion */

	num_frames = length / audio_format_frame_size(&encoder->audio_format);
	num_samples = num_frames * encoder->audio_format.channels;

	switch (encoder->audio_format.format) {
	case SAMPLE_FORMAT_S8:
		exbuffer = pcm_buffer_get(&encoder->expand_buffer, length*4);
		pcm8_to_flac(exbuffer, data, num_samples);
		buffer = exbuffer;
		break;

	case SAMPLE_FORMAT_S16:
		exbuffer = pcm_buffer_get(&encoder->expand_buffer, length*2);
		pcm16_to_flac(exbuffer, data, num_samples);
		buffer = exbuffer;
		break;

	case SAMPLE_FORMAT_S24_P32:
	case SAMPLE_FORMAT_S32:
		/* nothing need to be done; format is the same for
		   both mpd and libFLAC */
		buffer = data;
		break;
	}

	/* feed samples to encoder */

	if (!FLAC__stream_encoder_process_interleaved(encoder->fse, buffer,
							num_frames)) {
		g_set_error(error, flac_encoder_quark(), 0,
			    "flac encoder process failed");
		return false;
	}

	return true;
}
Esempio n. 11
0
static bool
lame_encoder_write(struct encoder *_encoder,
		   const void *data, size_t length,
		   G_GNUC_UNUSED GError **error)
{
	struct lame_encoder *encoder = (struct lame_encoder *)_encoder;
	unsigned num_frames;
	float *left, *right;
	const int16_t *src = (const int16_t*)data;
	unsigned int i;
	int bytes_out;

	assert(encoder->buffer_length == 0);

	num_frames =
		length / audio_format_frame_size(&encoder->audio_format);
	left = g_malloc(sizeof(left[0]) * num_frames);
	right = g_malloc(sizeof(right[0]) * num_frames);

	/* this is for only 16-bit audio */

	for (i = 0; i < num_frames; i++) {
		left[i] = *src++;
		right[i] = *src++;
	}

	bytes_out = lame_encode_buffer_float(encoder->gfp, left, right,
					     num_frames, encoder->buffer,
					     sizeof(encoder->buffer));

	g_free(left);
	g_free(right);

	if (bytes_out < 0) {
		g_set_error(error, lame_encoder_quark(), 0,
			    "lame encoder failed");
		return false;
	}

	encoder->buffer_length = (size_t)bytes_out;
	return true;
}
Esempio n. 12
0
static bool
vorbis_encoder_write(struct encoder *_encoder,
		     const void *data, size_t length,
		     G_GNUC_UNUSED GError **error)
{
	struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
	unsigned num_frames;

	num_frames = length / audio_format_frame_size(&encoder->audio_format);

	/* this is for only 16-bit audio */

	pcm16_to_vorbis_buffer(vorbis_analysis_buffer(&encoder->vd,
						      num_frames),
			       (const int16_t *)data,
			       num_frames, encoder->audio_format.channels);

	vorbis_analysis_wrote(&encoder->vd, num_frames);
	vorbis_encoder_blockout(encoder);
	return true;
}
Esempio n. 13
0
static const char *
ao_chunk_data(struct audio_output *ao, const struct music_chunk *chunk,
              struct filter *replay_gain_filter,
              unsigned *replay_gain_serial_p,
              size_t *length_r)
{
    assert(chunk != NULL);
    assert(!music_chunk_is_empty(chunk));
    assert(music_chunk_check_format(chunk, &ao->in_audio_format));

    const char *data = chunk->data;
    size_t length = chunk->length;

    (void)ao;

    assert(length % audio_format_frame_size(&ao->in_audio_format) == 0);

    if (length > 0 && replay_gain_filter != NULL) {
        if (chunk->replay_gain_serial != *replay_gain_serial_p) {
            replay_gain_filter_set_info(replay_gain_filter,
                                        chunk->replay_gain_serial != 0
                                        ? &chunk->replay_gain_info
                                        : NULL);
            *replay_gain_serial_p = chunk->replay_gain_serial;
        }

        GError *error = NULL;
        data = filter_filter(replay_gain_filter, data, length,
                             &length, &error);
        if (data == NULL) {
            g_warning("\"%s\" [%s] failed to filter: %s",
                      ao->name, ao->plugin->name, error->message);
            g_error_free(error);
            return NULL;
        }
    }

    *length_r = length;
    return data;
}
Esempio n. 14
0
static bool
osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error)
{
	struct osx_output *od = (struct osx_output *)ao;

	AudioStreamBasicDescription stream_description;
	stream_description.mSampleRate = audio_format->sample_rate;
	stream_description.mFormatID = kAudioFormatLinearPCM;
	stream_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;

	switch (audio_format->format) {
	case SAMPLE_FORMAT_S8:
		stream_description.mBitsPerChannel = 8;
		break;

	case SAMPLE_FORMAT_S16:
		stream_description.mBitsPerChannel = 16;
		break;

	case SAMPLE_FORMAT_S32:
		stream_description.mBitsPerChannel = 32;
		break;

	default:
		audio_format->format = SAMPLE_FORMAT_S32;
		stream_description.mBitsPerChannel = 32;
		break;
	}

#if G_BYTE_ORDER == G_BIG_ENDIAN
	stream_description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
#endif

	stream_description.mBytesPerPacket =
		audio_format_frame_size(audio_format);
	stream_description.mFramesPerPacket = 1;
	stream_description.mBytesPerFrame = stream_description.mBytesPerPacket;
	stream_description.mChannelsPerFrame = audio_format->channels;

	ComponentResult result =
		AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat,
				     kAudioUnitScope_Input, 0,
				     &stream_description,
				     sizeof(stream_description));
	if (result != noErr) {
		g_set_error(error, osx_output_quark(), result,
			    "Unable to set format on OS X device");
		return false;
	}

	OSStatus status = AudioUnitInitialize(od->au);
	if (status != noErr) {
		g_set_error(error, osx_output_quark(), status,
			    "Unable to initialize OS X audio unit: %s",
			    GetMacOSStatusCommentString(status));
		return false;
	}

	/* create a buffer of 1s */
	od->buffer = fifo_buffer_new(audio_format->sample_rate *
				     audio_format_frame_size(audio_format));

	status = AudioOutputUnitStart(od->au);
	if (status != 0) {
		AudioUnitUninitialize(od->au);
		g_set_error(error, osx_output_quark(), status,
			    "unable to start audio output: %s",
			    GetMacOSStatusCommentString(status));
		return false;
	}

	return true;
}
static bool
ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk)
{
	const char *data = chunk->data;
	size_t size = chunk->length;
	GError *error = NULL;

	assert(ao != NULL);
	assert(ao->filter != NULL);
	assert(!music_chunk_is_empty(chunk));
	assert(music_chunk_check_format(chunk, &ao->in_audio_format));
	assert(size % audio_format_frame_size(&ao->in_audio_format) == 0);

	if (chunk->tag != NULL) {
		g_mutex_unlock(ao->mutex);
		ao_plugin_send_tag(ao->plugin, ao->data, chunk->tag);
		g_mutex_lock(ao->mutex);
	}

	/* update replay gain */

	if (ao->replay_gain_filter != NULL &&
	    chunk->replay_gain_serial != ao->replay_gain_serial) {
		replay_gain_filter_set_info(ao->replay_gain_filter,
					    chunk->replay_gain_serial != 0
					    ? &chunk->replay_gain_info
					    : NULL);
		ao->replay_gain_serial = chunk->replay_gain_serial;
	}

	if (size == 0)
		return true;

	data = filter_filter(ao->filter, data, size, &size, &error);
	if (data == NULL) {
		g_warning("\"%s\" [%s] failed to filter: %s",
			  ao->name, ao->plugin->name, error->message);
		g_error_free(error);

		ao_close(ao, false);

		/* don't automatically reopen this device for 10
		   seconds */
		ao->fail_timer = g_timer_new();
		return false;
	}

	while (size > 0 && ao->command == AO_COMMAND_NONE) {
		size_t nbytes;

		g_mutex_unlock(ao->mutex);
		nbytes = ao_plugin_play(ao->plugin, ao->data, data, size,
					&error);
		g_mutex_lock(ao->mutex);
		if (nbytes == 0) {
			/* play()==0 means failure */
			g_warning("\"%s\" [%s] failed to play: %s",
				  ao->name, ao->plugin->name, error->message);
			g_error_free(error);

			ao_close(ao, false);

			/* don't automatically reopen this device for
			   10 seconds */
			ao->fail_timer = g_timer_new();
			return false;
		}

		assert(nbytes <= size);
		assert(nbytes % audio_format_frame_size(&ao->out_audio_format) == 0);

		data += nbytes;
		size -= nbytes;
	}

	return true;
}
Esempio n. 16
0
/*
 * This does the main decoding thing.
 * Requires an already opened WavpackContext.
 */
static void
wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek)
{
	GError *error = NULL;
	bool is_float;
	enum sample_format sample_format;
	struct audio_format audio_format;
	format_samples_t format_samples;
	float total_time;
	int bytes_per_sample, output_sample_size;

	is_float = (WavpackGetMode(wpc) & MODE_FLOAT) != 0;
	sample_format =
		wavpack_bits_to_sample_format(is_float,
					      WavpackGetBytesPerSample(wpc));

	if (!audio_format_init_checked(&audio_format,
				       WavpackGetSampleRate(wpc),
				       sample_format,
				       WavpackGetNumChannels(wpc), &error)) {
		g_warning("%s", error->message);
		g_error_free(error);
		return;
	}

	if (is_float) {
		format_samples = format_samples_float;
	} else {
		format_samples = format_samples_int;
	}

	total_time = WavpackGetNumSamples(wpc);
	total_time /= audio_format.sample_rate;
	bytes_per_sample = WavpackGetBytesPerSample(wpc);
	output_sample_size = audio_format_frame_size(&audio_format);

	/* wavpack gives us all kind of samples in a 32-bit space */
	int32_t chunk[1024];
	const uint32_t samples_requested = G_N_ELEMENTS(chunk) /
		audio_format.channels;

	decoder_initialized(decoder, &audio_format, can_seek, total_time);

	enum decoder_command cmd = decoder_get_command(decoder);
	while (cmd != DECODE_COMMAND_STOP) {
		if (cmd == DECODE_COMMAND_SEEK) {
			if (can_seek) {
				unsigned where = decoder_seek_where(decoder) *
					audio_format.sample_rate;

				if (WavpackSeekSample(wpc, where)) {
					decoder_command_finished(decoder);
				} else {
					decoder_seek_error(decoder);
				}
			} else {
				decoder_seek_error(decoder);
			}
		}

		uint32_t samples_got = WavpackUnpackSamples(wpc, chunk,
							    samples_requested);
		if (samples_got == 0)
			break;

		int bitrate = (int)(WavpackGetInstantBitrate(wpc) / 1000 +
				    0.5);
		format_samples(bytes_per_sample, chunk,
			       samples_got * audio_format.channels);

		cmd = decoder_data(decoder, NULL, chunk,
				   samples_got * output_sample_size,
				   bitrate);
	}
}
Esempio n. 17
0
enum decoder_command
decoder_data(struct decoder *decoder,
	     struct input_stream *is,
	     const void *_data, size_t length,
	     uint16_t kbit_rate)
{
	struct decoder_control *dc = decoder->dc;
	const char *data = _data;
	GError *error = NULL;
	enum decoder_command cmd;

	assert(dc->state == DECODE_STATE_DECODE);
	assert(dc->pipe != NULL);
	assert(length % audio_format_frame_size(&dc->in_audio_format) == 0);

	decoder_lock(dc);
	cmd = decoder_get_virtual_command(decoder);
	decoder_unlock(dc);

	if (cmd == DECODE_COMMAND_STOP || cmd == DECODE_COMMAND_SEEK ||
	    length == 0)
		return cmd;

	/* send stream tags */

	if (update_stream_tag(decoder, is)) {
		if (decoder->decoder_tag != NULL) {
			/* merge with tag from decoder plugin */
			struct tag *tag;

			tag = tag_merge(decoder->decoder_tag,
					decoder->stream_tag);
			cmd = do_send_tag(decoder, is, tag);
			tag_free(tag);
		} else
			/* send only the stream tag */
			cmd = do_send_tag(decoder, is, decoder->stream_tag);

		if (cmd != DECODE_COMMAND_NONE)
			return cmd;
	}

	if (!audio_format_equals(&dc->in_audio_format, &dc->out_audio_format)) {
		data = pcm_convert(&decoder->conv_state,
				   &dc->in_audio_format, data, length,
				   &dc->out_audio_format, &length,
				   &error);
		if (data == NULL) {
			/* the PCM conversion has failed - stop
			   playback, since we have no better way to
			   bail out */
			g_warning("%s", error->message);
			return DECODE_COMMAND_STOP;
		}
	}

	while (length > 0) {
		struct music_chunk *chunk;
		char *dest;
		size_t nbytes;
		bool full;

		chunk = decoder_get_chunk(decoder, is);
		if (chunk == NULL) {
			assert(dc->command != DECODE_COMMAND_NONE);
			return dc->command;
		}

		dest = music_chunk_write(chunk, &dc->out_audio_format,
					 decoder->timestamp -
					 dc->song->start_ms / 1000.0,
					 kbit_rate, &nbytes);
		if (dest == NULL) {
			/* the chunk is full, flush it */
			decoder_flush_chunk(decoder);
			player_lock_signal();
			continue;
		}

		assert(nbytes > 0);

		if (nbytes > length)
			nbytes = length;

		/* copy the buffer */

		memcpy(dest, data, nbytes);

		/* expand the music pipe chunk */

		full = music_chunk_expand(chunk, &dc->out_audio_format, nbytes);
		if (full) {
			/* the chunk is full, flush it */
			decoder_flush_chunk(decoder);
			player_lock_signal();
		}

		data += nbytes;
		length -= nbytes;

		decoder->timestamp += (double)nbytes /
			audio_format_time_to_size(&dc->out_audio_format);

		if (dc->end_ms > 0 &&
		    decoder->timestamp >= dc->end_ms / 1000.0)
			/* the end of this range has been reached:
			   stop decoding */
			return DECODE_COMMAND_STOP;
	}

	return DECODE_COMMAND_NONE;
}
Esempio n. 18
0
static bool
osx_output_open(void *data, struct audio_format *audio_format, GError **error)
{
	struct osx_output *od = data;
	ComponentDescription desc;
	Component comp;
	AURenderCallbackStruct callback;
	AudioStreamBasicDescription stream_description;
	OSStatus status;
	ComponentResult result;

	desc.componentType = kAudioUnitType_Output;
	desc.componentSubType = kAudioUnitSubType_DefaultOutput;
	desc.componentManufacturer = kAudioUnitManufacturer_Apple;
	desc.componentFlags = 0;
	desc.componentFlagsMask = 0;

	comp = FindNextComponent(NULL, &desc);
	if (comp == 0) {
		g_set_error(error, osx_output_quark(), 0,
			    "Error finding OS X component");
		return false;
	}

	status = OpenAComponent(comp, &od->au);
	if (status != noErr) {
		g_set_error(error, osx_output_quark(), 0,
			    "Unable to open OS X component: %s",
			    GetMacOSStatusCommentString(status));
		return false;
	}

	status = AudioUnitInitialize(od->au);
	if (status != noErr) {
		CloseComponent(od->au);
		g_set_error(error, osx_output_quark(), 0,
			    "Unable to initialize OS X audio unit: %s",
			    GetMacOSStatusCommentString(status));
		return false;
	}

	callback.inputProc = osx_render;
	callback.inputProcRefCon = od;

	result = AudioUnitSetProperty(od->au,
				      kAudioUnitProperty_SetRenderCallback,
				      kAudioUnitScope_Input, 0,
				      &callback, sizeof(callback));
	if (result != noErr) {
		AudioUnitUninitialize(od->au);
		CloseComponent(od->au);
		g_set_error(error, osx_output_quark(), 0,
			    "unable to set callback for OS X audio unit");
		return false;
	}

	stream_description.mSampleRate = audio_format->sample_rate;
	stream_description.mFormatID = kAudioFormatLinearPCM;
	stream_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
#if G_BYTE_ORDER == G_BIG_ENDIAN
	stream_description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
#endif

	stream_description.mBytesPerPacket =
		audio_format_frame_size(audio_format);
	stream_description.mFramesPerPacket = 1;
	stream_description.mBytesPerFrame = stream_description.mBytesPerPacket;
	stream_description.mChannelsPerFrame = audio_format->channels;

	switch (audio_format->format) {
	case SAMPLE_FORMAT_S8:
		stream_description.mBitsPerChannel = 8;
		break;

	case SAMPLE_FORMAT_S16:
		stream_description.mBitsPerChannel = 16;
		break;

	default:
		audio_format->format = SAMPLE_FORMAT_S16;
		stream_description.mBitsPerChannel = 16;
		break;
	}

	result = AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat,
				      kAudioUnitScope_Input, 0,
				      &stream_description,
				      sizeof(stream_description));
	if (result != noErr) {
		AudioUnitUninitialize(od->au);
		CloseComponent(od->au);
		g_set_error(error, osx_output_quark(), 0,
			    "Unable to set format on OS X device");
		return false;
	}

	/* create a buffer of 1s */
	od->buffer_size = (audio_format->sample_rate) *
		audio_format_frame_size(audio_format);
	od->buffer = g_realloc(od->buffer, od->buffer_size);

	od->pos = 0;
	od->len = 0;

	status = AudioOutputUnitStart(od->au);
	if (status != 0) {
		g_set_error(error, osx_output_quark(), 0,
			    "unable to start audio output: %s",
			    GetMacOSStatusCommentString(status));
		return false;
	}

	return true;
}
Esempio n. 19
0
int main(int argc, char **argv)
{
	struct audio_format audio_format;
	struct audio_format_string af_string;
	bool success;
	GError *error = NULL;
	struct filter *filter;
	const struct audio_format *out_audio_format;
	char buffer[4096];
	size_t frame_size;

	if (argc < 3 || argc > 4) {
		g_printerr("Usage: run_filter CONFIG NAME [FORMAT] <IN\n");
		return 1;
	}

	audio_format_init(&audio_format, 44100, SAMPLE_FORMAT_S16, 2);

	/* initialize GLib */

	g_thread_init(NULL);
	g_log_set_default_handler(my_log_func, NULL);

	/* read configuration file (mpd.conf) */

	config_global_init();
	success = config_read_file(argv[1], &error);
	if (!success) {
		g_printerr("%s:", error->message);
		g_error_free(error);
		return 1;
	}

	/* parse the audio format */

	if (argc > 3) {
		success = audio_format_parse(&audio_format, argv[3],
					     false, &error);
		if (!success) {
			g_printerr("Failed to parse audio format: %s\n",
				   error->message);
			g_error_free(error);
			return 1;
		}
	}

	/* initialize the filter */

	filter = load_filter(argv[2]);
	if (filter == NULL)
		return 1;

	/* open the filter */

	out_audio_format = filter_open(filter, &audio_format, &error);
	if (out_audio_format == NULL) {
		g_printerr("Failed to open filter: %s\n", error->message);
		g_error_free(error);
		filter_free(filter);
		return 1;
	}

	g_printerr("audio_format=%s\n",
		   audio_format_to_string(out_audio_format, &af_string));

	frame_size = audio_format_frame_size(&audio_format);

	/* play */

	while (true) {
		ssize_t nbytes;
		size_t length;
		const void *dest;

		nbytes = read(0, buffer, sizeof(buffer));
		if (nbytes <= 0)
			break;

		dest = filter_filter(filter, buffer, (size_t)nbytes,
				     &length, &error);
		if (dest == NULL) {
			g_printerr("Filter failed: %s\n", error->message);
			filter_close(filter);
			filter_free(filter);
			return 1;
		}

		nbytes = write(1, dest, length);
		if (nbytes < 0) {
			g_printerr("Failed to write: %s\n", strerror(errno));
			filter_close(filter);
			filter_free(filter);
			return 1;
		}
	}

	/* cleanup and exit */

	filter_close(filter);
	filter_free(filter);

	config_global_finish();

	return 0;
}
Esempio n. 20
0
int main(int argc, char **argv)
{
	struct audio_output ao;
	struct audio_format audio_format;
	struct audio_format_string af_string;
	bool success;
	GError *error = NULL;
	char buffer[4096];
	ssize_t nbytes;
	size_t frame_size, length = 0, play_length, consumed;

	if (argc < 3 || argc > 4) {
		g_printerr("Usage: run_output CONFIG NAME [FORMAT] <IN\n");
		return 1;
	}

	audio_format_init(&audio_format, 44100, SAMPLE_FORMAT_S16, 2);

	g_thread_init(NULL);

	/* read configuration file (mpd.conf) */

	config_global_init();
	success = config_read_file(argv[1], &error);
	if (!success) {
		g_printerr("%s:", error->message);
		g_error_free(error);
		return 1;
	}

	/* initialize the audio output */

	if (!load_audio_output(&ao, argv[2]))
		return 1;

	/* parse the audio format */

	if (argc > 3) {
		success = audio_format_parse(&audio_format, argv[3],
					     false, &error);
		if (!success) {
			g_printerr("Failed to parse audio format: %s\n",
				   error->message);
			g_error_free(error);
			return 1;
		}
	}

	/* open the audio output */

	success = ao_plugin_open(ao.plugin, ao.data, &audio_format, &error);
	if (!success) {
		g_printerr("Failed to open audio output: %s\n",
			   error->message);
		g_error_free(error);
		return 1;
	}

	g_printerr("audio_format=%s\n",
		   audio_format_to_string(&audio_format, &af_string));

	frame_size = audio_format_frame_size(&audio_format);

	/* play */

	while (true) {
		if (length < sizeof(buffer)) {
			nbytes = read(0, buffer + length, sizeof(buffer) - length);
			if (nbytes <= 0)
				break;

			length += (size_t)nbytes;
		}

		play_length = (length / frame_size) * frame_size;
		if (play_length > 0) {
			consumed = ao_plugin_play(ao.plugin, ao.data,
						  buffer, play_length,
						  &error);
			if (consumed == 0) {
				g_printerr("Failed to play: %s\n",
					   error->message);
				g_error_free(error);
				return 1;
			}

			assert(consumed <= length);
			assert(consumed % frame_size == 0);

			length -= consumed;
			memmove(buffer, buffer + consumed, length);
		}
	}

	/* cleanup and exit */

	ao_plugin_close(ao.plugin, ao.data);
	ao_plugin_finish(ao.plugin, ao.data);
	g_mutex_free(ao.mutex);

	config_global_finish();

	return 0;
}
Esempio n. 21
0
/*
 * This does the main decoding thing.
 * Requires an already opened WavpackContext.
 */
static void
wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek,
	       struct replay_gain_info *replay_gain_info)
{
	struct audio_format audio_format;
	format_samples_t format_samples;
	char chunk[CHUNK_SIZE];
	int samples_requested, samples_got;
	float total_time, current_time;
	int bytes_per_sample, output_sample_size;
	int position;

	audio_format.sample_rate = WavpackGetSampleRate(wpc);
	audio_format.channels = WavpackGetReducedChannels(wpc);
	audio_format.bits = WavpackGetBitsPerSample(wpc);

	/* round bitwidth to 8-bit units */
	audio_format.bits = (audio_format.bits + 7) & (~7);
	/* mpd handles max 24-bit samples */
	if (audio_format.bits > 24) {
		audio_format.bits = 24;
	}

	if (!audio_format_valid(&audio_format)) {
		g_warning("Invalid audio format: %u:%u:%u\n",
			  audio_format.sample_rate,
			  audio_format.bits,
			  audio_format.channels);
		return;
	}

	if ((WavpackGetMode(wpc) & MODE_FLOAT) == MODE_FLOAT) {
		format_samples = format_samples_float;
	} else {
		format_samples = format_samples_int;
	}

	total_time = WavpackGetNumSamples(wpc);
	total_time /= audio_format.sample_rate;
	bytes_per_sample = WavpackGetBytesPerSample(wpc);
	output_sample_size = audio_format_frame_size(&audio_format);

	/* wavpack gives us all kind of samples in a 32-bit space */
	samples_requested = sizeof(chunk) / (4 * audio_format.channels);

	decoder_initialized(decoder, &audio_format, can_seek, total_time);

	position = 0;

	do {
		if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) {
			if (can_seek) {
				int where;

				where = decoder_seek_where(decoder);
				where *= audio_format.sample_rate;
				if (WavpackSeekSample(wpc, where)) {
					position = where;
					decoder_command_finished(decoder);
				} else {
					decoder_seek_error(decoder);
				}
			} else {
				decoder_seek_error(decoder);
			}
		}

		if (decoder_get_command(decoder) == DECODE_COMMAND_STOP) {
			break;
		}

		samples_got = WavpackUnpackSamples(
			wpc, (int32_t *)chunk, samples_requested
		);
		if (samples_got > 0) {
			int bitrate = (int)(WavpackGetInstantBitrate(wpc) /
			              1000 + 0.5);
			position += samples_got;
			current_time = position;
			current_time /= audio_format.sample_rate;

			format_samples(
				bytes_per_sample, chunk,
				samples_got * audio_format.channels
			);

			decoder_data(
				decoder, NULL, chunk,
				samples_got * output_sample_size,
				current_time, bitrate,
				replay_gain_info
			);
		}
	} while (samples_got > 0);
}
Esempio n. 22
0
enum decoder_command
decoder_data(struct decoder *decoder,
	     struct input_stream *is,
	     const void *_data, size_t length,
	     float data_time, uint16_t bitRate,
	     struct replay_gain_info *replay_gain_info)
{
	const char *data = _data;

	assert(dc.state == DECODE_STATE_DECODE);
	assert(length % audio_format_frame_size(&dc.in_audio_format) == 0);

	if (dc.command == DECODE_COMMAND_STOP ||
	    dc.command == DECODE_COMMAND_SEEK ||
	    length == 0)
		return dc.command;

	/* send stream tags */

	if (update_stream_tag(decoder, is)) {
		enum decoder_command cmd;

		if (decoder->decoder_tag != NULL) {
			/* merge with tag from decoder plugin */
			struct tag *tag;

			tag = tag_merge(decoder->stream_tag,
					decoder->decoder_tag);
			cmd = do_send_tag(decoder, is, tag);
			tag_free(tag);
		} else
			/* send only the stream tag */
			cmd = do_send_tag(decoder, is, decoder->stream_tag);

		if (cmd != DECODE_COMMAND_NONE)
			return cmd;
	}

	if (!audio_format_equals(&dc.in_audio_format, &dc.out_audio_format)) {
		data = pcm_convert(&decoder->conv_state,
				   &dc.in_audio_format, data, length,
				   &dc.out_audio_format, &length);

		/* under certain circumstances, pcm_convert() may
		   return an empty buffer - this condition should be
		   investigated further, but for now, do this check as
		   a workaround: */
		if (data == NULL)
			return DECODE_COMMAND_NONE;
	}

	while (length > 0) {
		struct music_chunk *chunk;
		char *dest;
		size_t nbytes;
		bool full;

		chunk = decoder_get_chunk(decoder, is);
		if (chunk == NULL) {
			assert(dc.command != DECODE_COMMAND_NONE);
			return dc.command;
		}

		dest = music_chunk_write(chunk, &dc.out_audio_format,
					 data_time, bitRate, &nbytes);
		if (dest == NULL) {
			/* the chunk is full, flush it */
			decoder_flush_chunk(decoder);
			notify_signal(&pc.notify);
			continue;
		}

		assert(nbytes > 0);

		if (nbytes > length)
			nbytes = length;

		/* copy the buffer */

		memcpy(dest, data, nbytes);

		/* apply replay gain or normalization */

		if (replay_gain_info != NULL &&
		    replay_gain_mode != REPLAY_GAIN_OFF)
			replay_gain_apply(replay_gain_info, dest, nbytes,
					  &dc.out_audio_format);
		else if (normalizationEnabled)
			normalizeData(dest, nbytes, &dc.out_audio_format);

		/* expand the music pipe chunk */

		full = music_chunk_expand(chunk, &dc.out_audio_format, nbytes);
		if (full) {
			/* the chunk is full, flush it */
			decoder_flush_chunk(decoder);
			notify_signal(&pc.notify);
		}

		data += nbytes;
		length -= nbytes;
	}

	return DECODE_COMMAND_NONE;
}