1
// ------------------------------------------------------------------------
2
// audioio-ogg.cpp: Interface for ogg vorbis decoders and encoders.
3
// Copyright (C) 2000-2002,2004-2005 Kai Vehmanen
5
// This program is free software; you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation; either version 2 of the License, or
8
// (at your option) any later version.
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
// GNU General Public License for more details.
15
// You should have received a copy of the GNU General Public License
16
// along with this program; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
// ------------------------------------------------------------------------
21
#include <cstdlib> /* atol() */
22
#include <unistd.h> /* stat() */
23
#include <sys/stat.h> /* stat() */
25
#include <kvu_message_item.h>
26
#include <kvu_numtostr.h>
28
#include "audioio-ogg.h"
30
#include "eca-logger.h"
32
string OGG_VORBIS_INTERFACE::default_input_cmd = "ogg123 -d raw -o byteorder:%E --file=- %f";
33
string OGG_VORBIS_INTERFACE::default_output_cmd = "oggenc -b %B --raw --raw-bits=%b --raw-chan=%c --raw-rate=%s --raw-endianness 0 --output=%f -";
34
long int OGG_VORBIS_INTERFACE::default_output_default_bitrate = 128000;
36
void OGG_VORBIS_INTERFACE::set_input_cmd(const std::string& value) { OGG_VORBIS_INTERFACE::default_input_cmd = value; }
37
void OGG_VORBIS_INTERFACE::set_output_cmd(const std::string& value) { OGG_VORBIS_INTERFACE::default_output_cmd = value; }
39
OGG_VORBIS_INTERFACE::OGG_VORBIS_INTERFACE(const std::string& name)
43
bitrate_rep = OGG_VORBIS_INTERFACE::default_output_default_bitrate;
46
OGG_VORBIS_INTERFACE::~OGG_VORBIS_INTERFACE(void)
48
if (is_open() == true) {
53
void OGG_VORBIS_INTERFACE::open(void) throw (AUDIO_IO::SETUP_ERROR &)
55
std::string urlprefix;
56
triggered_rep = false;
58
if (io_mode() == io_read) {
60
int ret = ::stat(label().c_str(), &buf);
62
size_t offset = label().find_first_of("://");
63
if (offset == std::string::npos) {
64
throw(SETUP_ERROR(SETUP_ERROR::io_mode, "AUDIOIO-OGG: Can't open file " + label() + "."));
67
urlprefix = std::string(label(), 0, offset);
68
ECA_LOG_MSG(ECA_LOGGER::user_objects, "(audioio-ogg) Found url; protocol '" + urlprefix + "'.");
72
/* decoder supports: nothing configurable nor fixed
74
* FIXME: we have no idea about the audio format of the
75
* stream we get from the decoder... ybe we should force the decoder
76
* to generate RIFF wave to a named pipe and parse the header...?
80
/* encoder supports: coding, channel-count and srate configurable,
81
* fixed to little endian */
82
ECA_AUDIO_FORMAT::set_sample_endianess(ECA_AUDIO_FORMAT::se_little);
88
void OGG_VORBIS_INTERFACE::close(void)
90
if (pid_of_child() > 0) {
91
ECA_LOG_MSG(ECA_LOGGER::user_objects, "(audioio-mp3) Cleaning child process." + kvu_numtostr(pid_of_child()) + ".");
93
triggered_rep = false;
99
long int OGG_VORBIS_INTERFACE::read_samples(void* target_buffer, long int samples)
101
if (triggered_rep != true) {
102
triggered_rep = true;
103
fork_input_process();
107
bytes_rep = std::fread(target_buffer, 1, frame_size() * samples, f1_rep);
113
if (bytes_rep < samples * frame_size() || bytes_rep == 0) {
114
if (position_in_samples() == 0)
115
ECA_LOG_MSG(ECA_LOGGER::info, "(audioio-ogg) Can't start process \"" + fork_command() + "\". Please check your ~/.ecasound/ecasoundrc.");
117
triggered_rep = false;
120
finished_rep = false;
122
return(bytes_rep / frame_size());
125
void OGG_VORBIS_INTERFACE::write_samples(void* target_buffer, long int samples)
127
if (triggered_rep != true) {
128
triggered_rep = true;
129
fork_output_process();
132
if (wait_for_child() != true) {
134
triggered_rep = false;
137
if (filedes_rep > 0) {
138
bytes_rep = ::write(filedes_rep, target_buffer, frame_size() * samples);
143
if (bytes_rep < frame_size() * samples || bytes_rep == 0) {
145
triggered_rep = false;
147
else finished_rep = false;
151
void OGG_VORBIS_INTERFACE::seek_position(void) {
152
if (pid_of_child() > 0) {
153
ECA_LOG_MSG(ECA_LOGGER::user_objects, "(audioio-ogg) Cleaning child process." + kvu_numtostr(pid_of_child()) + ".");
155
triggered_rep = false;
157
set_position_in_samples(0);
160
void OGG_VORBIS_INTERFACE::set_parameter(int param, string value)
168
long int numvalue = atol(value.c_str());
170
bitrate_rep = numvalue;
172
bitrate_rep = OGG_VORBIS_INTERFACE::default_output_default_bitrate;
177
string OGG_VORBIS_INTERFACE::get_parameter(int param) const
184
return(kvu_numtostr(bitrate_rep));
189
void OGG_VORBIS_INTERFACE::fork_input_process(void)
191
string command = OGG_VORBIS_INTERFACE::default_input_cmd;
193
// replace with 'little/big' byteorder
194
if (command.find("%E") != string::npos) {
195
string byteorder ("big");
196
if (sample_endianess() == ECA_AUDIO_FORMAT::se_little) byteorder = "little";
197
command.replace(command.find("%E"), 2, byteorder);
200
set_fork_command(command);
201
set_fork_file_name(label());
202
set_fork_pipe_name();
203
fork_child_for_read();
204
if (child_fork_succeeded() == true) {
205
/* NOTE: the file description will be closed by
206
* AUDIO_IO_FORKED_STREAM::clean_child() */
207
filedes_rep = file_descriptor();
208
f1_rep = fdopen(filedes_rep, "r"); /* not part of <cstdio> */
211
triggered_rep = false;
218
void OGG_VORBIS_INTERFACE::fork_output_process(void)
220
ECA_LOG_MSG(ECA_LOGGER::info, "(audioio-ogg) Starting to encode " + label() + " with vorbize.");
221
string command = OGG_VORBIS_INTERFACE::default_output_cmd;
223
// replace with bitrate
224
if (command.find("%B") != string::npos) {
225
command.replace(command.find("%B"), 2, kvu_numtostr((long int)(bitrate_rep / 1000)));
228
set_fork_command(command);
229
set_fork_file_name(label());
231
set_fork_bits(bits());
232
set_fork_channels(channels());
233
set_fork_sample_rate(samples_per_second());
235
fork_child_for_write();
236
if (child_fork_succeeded() == true) {
237
filedes_rep = file_descriptor();