1
// ------------------------------------------------------------------------
2
// audioio-db-client.cpp: Client class for double-buffering providing
3
// additional layer of buffering for objects
4
// derived from AUDIO_IO.
5
// Copyright (C) 2000-2005,2009,2011 Kai Vehmanen
8
// eca-style-version: 3
10
// This program is free software; you can redistribute it and/or modify
11
// it under the terms of the GNU General Public License as published by
12
// the Free Software Foundation; either version 2 of the License, or
13
// (at your option) any later version.
15
// This program is distributed in the hope that it will be useful,
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
// GNU General Public License for more details.
20
// You should have received a copy of the GNU General Public License
21
// along with this program; if not, write to the Free Software
22
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
// ------------------------------------------------------------------------
25
#include <unistd.h> /* open(), close() */
28
#include <kvu_numtostr.h>
30
#include "samplebuffer.h"
31
#include "eca-logger.h"
32
#include "audioio-db-client.h"
35
* Constructor. The given client object is registered to
36
* the given db server as a client object.
38
* Ownership of 'aobject' is transfered to this db client
39
* object if 'transfer_ownership' is true.
41
AUDIO_IO_DB_CLIENT::AUDIO_IO_DB_CLIENT (AUDIO_IO_DB_SERVER *pserver,
43
bool transfer_ownership)
44
: pserver_repp(pserver),
45
free_child_rep(transfer_ownership)
51
recursing_rep = false;
53
ECA_LOG_MSG(ECA_LOGGER::user_objects,
54
std::string("DB-client created for ") +
58
// just in case the child object has already been configured
59
fetch_initial_child_data();
63
* Copy attributes from the proxied (child) object.
65
void AUDIO_IO_DB_CLIENT::fetch_initial_child_data(void)
67
// note! the child object is one that is configured
69
set_audio_format(child()->audio_format());
70
set_position_in_samples(child()->position_in_samples());
71
set_length_in_samples(child()->length_in_samples());
72
set_buffersize(child()->buffersize());
73
set_io_mode(child()->io_mode());
74
set_label(child()->label());
75
toggle_nonblocking_mode(child()->nonblocking_mode());
79
* Desctructor. Unregisters the client from the db
82
AUDIO_IO_DB_CLIENT::~AUDIO_IO_DB_CLIENT(void)
84
ECA_LOG_MSG(ECA_LOGGER::user_objects, "destructor " + label() + ".");
86
if (is_open() == true) {
90
if (pserver_repp != 0) {
91
bool was_running = false;
92
if (pserver_repp->is_running() == true) {
95
pserver_repp->wait_for_stop();
96
DBC_CHECK(pserver_repp->is_running() != true);
99
pserver_repp->unregister_client(child());
102
if (was_running == true) {
103
pserver_repp->start();
107
if (free_child_rep != true) {
108
/* to avoid deleting the original registered child */
109
release_child_no_delete();
113
std::cerr << "(audioio-db-client) There were total " << xruns_rep << " xruns." << std::endl;
117
* Whether all data has been processed? If opened in mode 'io_read',
118
* this means that end of stream has been reached. If opened in
119
* 'io_write' or 'io_readwrite' modes, finished status usually
120
* means that an error has occured (no space left, etc). After
121
* finished() has returned 'true', further calls to read_buffer()
122
* and/or write_buffer() won't process any data.
124
bool AUDIO_IO_DB_CLIENT::finished(void) const { return finished_rep; }
127
* Reads samples to buffer pointed by 'sbuf'. If necessary, the target
128
* buffer will be resized.
130
void AUDIO_IO_DB_CLIENT::read_buffer(SAMPLE_BUFFER* sbuf)
132
DBC_CHECK(pbuffer_repp != 0);
134
if (pbuffer_repp->read_space() > 0) {
135
SAMPLE_BUFFER* source = pbuffer_repp->sbufs_rep[pbuffer_repp->readptr_rep.get()];
136
sbuf->copy_all_content(*source);
137
pbuffer_repp->advance_read_pointer();
138
pserver_repp->signal_client_activity();
139
change_position_in_samples(sbuf->length_in_samples());
142
sbuf->number_of_channels(channels());
143
if (pbuffer_repp->finished_rep.get() == 1) {
145
sbuf->length_in_samples(0);
149
sbuf->length_in_samples(0);
151
std::cerr << "(audioio-db-client) WARNING: Underrun in reading from \""
153
<< "\". Trying to recover." << std::endl;
158
DBC_ENSURE(sbuf->number_of_channels() == channels());
163
* Writes all data from sample buffer pointed by 'sbuf'. Notes
164
* concerning read_buffer() also apply to this routine.
166
void AUDIO_IO_DB_CLIENT::write_buffer(SAMPLE_BUFFER* sbuf)
168
DBC_CHECK(pbuffer_repp != 0);
170
if (pbuffer_repp->write_space() > 0) {
171
SAMPLE_BUFFER* target = pbuffer_repp->sbufs_rep[pbuffer_repp->writeptr_rep.get()];
172
target->copy_all_content(*sbuf);
173
target->number_of_channels(channels());
174
pbuffer_repp->advance_write_pointer();
175
pserver_repp->signal_client_activity();
176
change_position_in_samples(sbuf->length_in_samples());
180
if (pbuffer_repp->finished_rep.get() == 1) finished_rep = true;
182
/* NOTE: not always rt-safe, but it's better to break rt-safety than
183
* to lose recorded data */
185
std::cerr << "(audioio-db-client) WARNING: Overrun in writing to \""
187
<< "\". Trying to recover." << std::endl;
191
pserver_repp->wait_for_full();
192
if (recursing_rep != true && pbuffer_repp->write_space() > 0) {
193
recursing_rep = true;
194
this->write_buffer(sbuf);
195
recursing_rep = false;
198
seek_position(position_in_samples()); // hack to force a restart of the db server
199
std::cerr << "(audioio-db-client) Serious trouble with the disk-io subsystem! (output)" << std::endl;
206
* Stops the DB server in case it's running.
207
* Returns true if server was running. The return
208
* value should be passed to restore_db_server_state()
211
bool AUDIO_IO_DB_CLIENT::pause_db_server_if_running(void)
213
bool was_running = false;
214
if (pserver_repp->is_running() == true) {
216
pserver_repp->stop();
217
pserver_repp->wait_for_stop();
218
DBC_CHECK(pserver_repp->is_running() != true);
224
void AUDIO_IO_DB_CLIENT::restore_db_server_state(bool was_running)
226
if (was_running == true) {
227
pserver_repp->start();
228
pserver_repp->wait_for_full();
229
DBC_CHECK(pserver_repp->is_running() == true);
234
* Seeks to the current position.
236
* Note! Seeking involves stopping the whole db
237
* server, so it's a costly operation.
239
SAMPLE_SPECS::sample_pos_t AUDIO_IO_DB_CLIENT::seek_position(SAMPLE_SPECS::sample_pos_t pos)
241
ECA_LOG_MSG(ECA_LOGGER::user_objects,
243
" to pos " + kvu_numtostr(pos) + ".");
244
SAMPLE_SPECS::sample_pos_t res =
245
child()->position_in_samples();
247
if (child()->supports_seeking() == true) {
248
bool was_running = pause_db_server_if_running();
250
child()->seek_position_in_samples(pos);
251
res = child()->position_in_samples();
252
if (pbuffer_repp != 0) {
253
pbuffer_repp->reset();
256
finished_rep = false;
258
restore_db_server_state(was_running);
261
/* note: important that we override the AUDIO_IO_PROXY
262
* default implementation as it does the wrong thing */
263
return AUDIO_IO::seek_position(res);
267
* Opens the child audio object (possibly in exclusive mode).
268
* This routine is meant for opening files and devices,
269
* loading libraries, etc.
271
void AUDIO_IO_DB_CLIENT::open(void) throw(AUDIO_IO::SETUP_ERROR&)
273
ECA_LOG_MSG(ECA_LOGGER::user_objects, "open " + label() + ".");
275
if (child()->is_open() != true) {
279
set_audio_format(child()->audio_format());
280
set_length_in_samples(child()->length_in_samples());
282
if (pbuffer_repp == 0) {
283
pserver_repp->register_client(child());
284
pbuffer_repp = pserver_repp->get_client_buffer(child());
286
for(unsigned int n = 0; n < pbuffer_repp->sbufs_rep.size(); n++) {
287
pbuffer_repp->sbufs_rep[n]->number_of_channels(channels());
288
pbuffer_repp->sbufs_rep[n]->length_in_samples(buffersize());
291
if (io_mode() == AUDIO_IO::io_read)
292
pbuffer_repp->io_mode_rep = AUDIO_IO::io_read;
294
pbuffer_repp->io_mode_rep = AUDIO_IO::io_write;
301
* Closes the child audio object. After calling this routine,
302
* all resources (ie. soundcard) must be freed
303
* (they can be used by other processes).
305
void AUDIO_IO_DB_CLIENT::close(void)
307
ECA_LOG_MSG(ECA_LOGGER::user_objects, "close " + label() + ".");
309
if (child()->is_open() == true) child()->close();
314
void AUDIO_IO_DB_CLIENT::start_io(void)
316
AUDIO_IO_PROXY::start_io();
318
/* note: child may have changed its position after
319
* start_io() is issued (via AUDIO_IO_PROXY::start_io() */
321
if (child()->supports_seeking() == true) {
322
bool was_running = pause_db_server_if_running();
324
set_position_in_samples(child()->position_in_samples());
326
/* as position might have changed, flush the buffers */
327
if (pbuffer_repp != 0) {
328
pbuffer_repp->reset();
331
restore_db_server_state(was_running);
335
void AUDIO_IO_DB_CLIENT::stop_io(void)
337
AUDIO_IO_PROXY::stop_io();