<commit_before>/*-
 * Copyright (C) 2012  University Radio York Computing Team
 *
 * This file is a part of playslave.
 *
 * playslave is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * playslave is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * playslave; if not, write to the Free Software Foundation, Inc., 51 Franklin
 * Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#define _POSIX_C_SOURCE 200809

/**  INCLUDES  ****************************************************************/

extern "C" {
#ifdef WIN32
#define inline __inline
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#ifdef WIN32
#undef inline
#endif
}

#include <portaudio.h>

#include "contrib/pa_ringbuffer.h"

#include "audio.h"
#include "audio_av.h"
#include "audio_cb.h"		/* audio_cb_play */
#include "constants.h"

audio::audio(const std::string &path, int device)
{
	this->last_err = E_INCOMPLETE;
	this->av = std::unique_ptr<au_in>(new au_in(path));

	init_sink(device);
	init_ring_buf(this->av->samples2bytes(1L));

	this->frame_ptr = nullptr;
	this->frame_samples = 0;

	this->callback = [this](char *out, unsigned long frames_per_buf) {
		return this->cb_play(out, frames_per_buf);
	};
}

audio::~audio()
{
	free_ring_buf();

	if (this->out_strm != nullptr) {
		Pa_CloseStream(this->out_strm);
		this->out_strm = nullptr;
		dbug("closed output stream");
	}
}

void
audio::start()
{
	PaError		pa_err;
	enum error	err = E_OK;

	spin_up();
	pa_err = Pa_StartStream(this->out_strm);
	if (pa_err) {
		throw error(E_INTERNAL_ERROR, "couldn't start stream");
	}

	dbug("audio started");
}

void
audio::stop()
{
	PaError		pa_err;
	enum error	err = E_OK;

	pa_err = Pa_AbortStream(this->out_strm);
	if (pa_err) {
		throw error(E_INTERNAL_ERROR, "couldn't stop stream");
	}

	dbug("audio stopped");

	/* TODO: Possibly recover from dropping frames due to abort. */
}

/* Returns the last decoding error, or E_OK if the last decode succeeded. */
enum error
audio::last_error()
{
	return this->last_err;
}

/* Checks to see if audio playback has halted of its own accord.
 *
 * If audio is still playing, E_OK will be returned; otherwise the decoding
 * error that caused playback to halt will be returned.  E_UNKNOWN is returned
 * if playback has halted but the last error report was E_OK.
 */
bool
audio::halted()
{
	bool halted = !Pa_IsStreamActive(this->out_strm);

	if (halted && this->last_err == E_OK) {
		/* Abnormal stream halts with error being OK are weird... */
		throw E_UNKNOWN;
	}
	return halted;
}

/* Gets the current played position in the song, in microseconds.
 *
 * As this may be executing whilst the playing callback is running,
 * do not expect it to be highly accurate.
 */
uint64_t
audio::usec()
{
	return this->av->samples2usec(this->used_samples);
}

size_t
audio::samples2bytes(size_t samples)<commit_msg>Don't throw if the stream has halted nicely.<commit_after>/*-
 * Copyright (C) 2012  University Radio York Computing Team
 *
 * This file is a part of playslave.
 *
 * playslave is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * playslave is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * playslave; if not, write to the Free Software Foundation, Inc., 51 Franklin
 * Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#define _POSIX_C_SOURCE 200809

/**  INCLUDES  ****************************************************************/

extern "C" {
#ifdef WIN32
#define inline __inline
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#ifdef WIN32
#undef inline
#endif
}

#include <portaudio.h>

#include "contrib/pa_ringbuffer.h"

#include "audio.h"
#include "audio_av.h"
#include "audio_cb.h"		/* audio_cb_play */
#include "constants.h"

audio::audio(const std::string &path, int device)
{
	this->last_err = E_INCOMPLETE;
	this->av = std::unique_ptr<au_in>(new au_in(path));

	init_sink(device);
	init_ring_buf(this->av->samples2bytes(1L));

	this->frame_ptr = nullptr;
	this->frame_samples = 0;

	this->callback = [this](char *out, unsigned long frames_per_buf) {
		return this->cb_play(out, frames_per_buf);
	};
}

audio::~audio()
{
	free_ring_buf();

	if (this->out_strm != nullptr) {
		Pa_CloseStream(this->out_strm);
		this->out_strm = nullptr;
		dbug("closed output stream");
	}
}

void
audio::start()
{
	PaError		pa_err;
	enum error	err = E_OK;

	spin_up();
	pa_err = Pa_StartStream(this->out_strm);
	if (pa_err) {
		throw error(E_INTERNAL_ERROR, "couldn't start stream");
	}

	dbug("audio started");
}

void
audio::stop()
{
	PaError		pa_err;
	enum error	err = E_OK;

	pa_err = Pa_AbortStream(this->out_strm);
	if (pa_err) {
		throw error(E_INTERNAL_ERROR, "couldn't stop stream");
	}

	dbug("audio stopped");

	/* TODO: Possibly recover from dropping frames due to abort. */
}

/* Returns the last decoding error, or E_OK if the last decode succeeded. */
enum error
audio::last_error()
{
	return this->last_err;
}

/* Checks to see if audio playback has halted of its own accord.
 *
 * If audio is still playing, E_OK will be returned; otherwise the decoding
 * error that caused playback to halt will be returned.  E_UNKNOWN is returned
 * if playback has halted but the last error report was E_OK.
 */
bool
audio::halted()
{
	return !Pa_IsStreamActive(this->out_strm);
}

/* Gets the current played position in the song, in microseconds.
 *
 * As this may be executing whilst the playing callback is running,
 * do not expect it to be highly accurate.
 */
uint64_t
audio::usec()
{
	return this->av->samples2usec(this->used_samples);
}

size_t
audio::samples2bytes(size_t samples)
{'fraction_non_alphanumeric': 0.1285426668731609, 'fraction_numerical': 0.010221465076660987, 'mean_word_length': 4.3996655518394645, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 48, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1106389', 'n_tokens_mistral': 2223, 'n_tokens_neox': 2105, 'n_words': 720}