~ubuntu-branches/ubuntu/wily/ecasound/wily-proposed

« back to all changes in this revision

Viewing changes to libecasound/audioio-db-client.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghedini
  • Date: 2011-05-12 17:58:03 UTC
  • Revision ID: james.westby@ubuntu.com-20110512175803-zy3lodjecabt9r3v
Tags: upstream-2.8.0
ImportĀ upstreamĀ versionĀ 2.8.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
6
//
 
7
// Attributes:
 
8
//     eca-style-version: 3
 
9
//
 
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.
 
14
// 
 
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.
 
19
// 
 
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
// ------------------------------------------------------------------------
 
24
 
 
25
#include <unistd.h> /* open(), close() */
 
26
 
 
27
#include <kvu_dbc.h>
 
28
#include <kvu_numtostr.h>
 
29
 
 
30
#include "samplebuffer.h"
 
31
#include "eca-logger.h"
 
32
#include "audioio-db-client.h"
 
33
 
 
34
/**
 
35
 * Constructor. The given client object is registered to 
 
36
 * the given db server as a client object.
 
37
 *
 
38
 * Ownership of 'aobject' is transfered to this db client
 
39
 * object if 'transfer_ownership' is true.
 
40
 */
 
41
AUDIO_IO_DB_CLIENT::AUDIO_IO_DB_CLIENT (AUDIO_IO_DB_SERVER *pserver, 
 
42
                                        AUDIO_IO* aobject,
 
43
                                        bool transfer_ownership) 
 
44
  : pserver_repp(pserver),
 
45
    free_child_rep(transfer_ownership) 
 
46
{
 
47
  set_child(aobject);
 
48
  pbuffer_repp = 0;
 
49
  xruns_rep = 0;
 
50
  finished_rep = false;
 
51
  recursing_rep = false;
 
52
 
 
53
  ECA_LOG_MSG(ECA_LOGGER::user_objects, 
 
54
                std::string("DB-client created for ") +
 
55
                child()->label() +
 
56
                ".");
 
57
 
 
58
  // just in case the child object has already been configured
 
59
  fetch_initial_child_data();
 
60
}
 
61
 
 
62
/**
 
63
 * Copy attributes from the proxied (child) object.
 
64
 */
 
65
void AUDIO_IO_DB_CLIENT::fetch_initial_child_data(void)
 
66
{
 
67
  // note! the child object is one that is configured
 
68
  //       at this point
 
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());
 
76
}
 
77
 
 
78
/**
 
79
 * Desctructor. Unregisters the client from the db
 
80
 * server.
 
81
 */
 
82
AUDIO_IO_DB_CLIENT::~AUDIO_IO_DB_CLIENT(void)
 
83
{
 
84
  ECA_LOG_MSG(ECA_LOGGER::user_objects, "destructor " + label() + ".");
 
85
 
 
86
  if (is_open() == true) {
 
87
    close();
 
88
  }
 
89
 
 
90
  if (pserver_repp != 0) {
 
91
    bool was_running = false;
 
92
    if (pserver_repp->is_running() == true) {
 
93
      was_running = true;
 
94
      pserver_repp->stop();
 
95
      pserver_repp->wait_for_stop();
 
96
      DBC_CHECK(pserver_repp->is_running() != true);
 
97
    }
 
98
 
 
99
    pserver_repp->unregister_client(child());
 
100
    pbuffer_repp = 0;
 
101
 
 
102
    if (was_running == true) {
 
103
      pserver_repp->start();
 
104
    }
 
105
  }
 
106
  
 
107
  if (free_child_rep != true) {
 
108
    /* to avoid deleting the original registered child */
 
109
    release_child_no_delete();
 
110
  }
 
111
    
 
112
  if (xruns_rep > 0) 
 
113
    std::cerr << "(audioio-db-client) There were total " << xruns_rep << " xruns." << std::endl;
 
114
}
 
115
 
 
116
/**
 
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.
 
123
 */
 
124
bool AUDIO_IO_DB_CLIENT::finished(void) const { return finished_rep; }
 
125
 
 
126
/**
 
127
 * Reads samples to buffer pointed by 'sbuf'. If necessary, the target 
 
128
 * buffer will be resized.
 
129
 */
 
130
void AUDIO_IO_DB_CLIENT::read_buffer(SAMPLE_BUFFER* sbuf)
 
131
{
 
132
  DBC_CHECK(pbuffer_repp != 0);
 
133
 
 
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());
 
140
  }
 
141
  else {
 
142
    sbuf->number_of_channels(channels());
 
143
    if (pbuffer_repp->finished_rep.get() == 1) {
 
144
      finished_rep = true;
 
145
      sbuf->length_in_samples(0);
 
146
    }
 
147
    else {
 
148
      xruns_rep++;
 
149
      sbuf->length_in_samples(0);
 
150
 
 
151
      std::cerr << "(audioio-db-client) WARNING: Underrun in reading from \"" 
 
152
                << child()->label() 
 
153
                << "\". Trying to recover." << std::endl;
 
154
    }
 
155
  }
 
156
 
 
157
  // --------
 
158
  DBC_ENSURE(sbuf->number_of_channels() == channels());
 
159
  // --------
 
160
}
 
161
 
 
162
/**
 
163
 * Writes all data from sample buffer pointed by 'sbuf'. Notes
 
164
 * concerning read_buffer() also apply to this routine.
 
165
 */
 
166
void AUDIO_IO_DB_CLIENT::write_buffer(SAMPLE_BUFFER* sbuf)
 
167
{
 
168
  DBC_CHECK(pbuffer_repp != 0);
 
169
 
 
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());
 
177
    extend_position();
 
178
  }
 
179
  else {
 
180
    if (pbuffer_repp->finished_rep.get() == 1) finished_rep = true;
 
181
    else {
 
182
      /* NOTE: not always rt-safe, but it's better to break rt-safety than
 
183
       *       to lose recorded data */
 
184
 
 
185
      std::cerr << "(audioio-db-client) WARNING: Overrun in writing to \"" 
 
186
                << child()->label() 
 
187
                << "\". Trying to recover." << std::endl;
 
188
 
 
189
      xruns_rep++;
 
190
 
 
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;
 
196
      }
 
197
      else {
 
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;
 
200
      }
 
201
    }
 
202
  }
 
203
}
 
204
 
 
205
/**
 
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()
 
209
 * function.
 
210
 */
 
211
bool AUDIO_IO_DB_CLIENT::pause_db_server_if_running(void)
 
212
{
 
213
  bool was_running = false;
 
214
  if (pserver_repp->is_running() == true) {
 
215
    was_running = true;
 
216
    pserver_repp->stop();
 
217
    pserver_repp->wait_for_stop();
 
218
    DBC_CHECK(pserver_repp->is_running() != true);
 
219
  }
 
220
 
 
221
  return was_running;
 
222
}
 
223
 
 
224
void AUDIO_IO_DB_CLIENT::restore_db_server_state(bool was_running)
 
225
{
 
226
  if (was_running == true) {
 
227
    pserver_repp->start();
 
228
    pserver_repp->wait_for_full();
 
229
    DBC_CHECK(pserver_repp->is_running() == true);
 
230
  }
 
231
}
 
232
 
 
233
/**
 
234
 * Seeks to the current position.
 
235
 *
 
236
 * Note! Seeking involves stopping the whole db 
 
237
 *       server, so it's a costly operation.
 
238
 */
 
239
SAMPLE_SPECS::sample_pos_t AUDIO_IO_DB_CLIENT::seek_position(SAMPLE_SPECS::sample_pos_t pos)
 
240
 
241
  ECA_LOG_MSG(ECA_LOGGER::user_objects, 
 
242
              "seek " + label() + 
 
243
              " to pos " + kvu_numtostr(pos) + ".");
 
244
  SAMPLE_SPECS::sample_pos_t res =
 
245
    child()->position_in_samples();
 
246
  
 
247
  if (child()->supports_seeking() == true) {
 
248
    bool was_running = pause_db_server_if_running();
 
249
 
 
250
    child()->seek_position_in_samples(pos);
 
251
    res = child()->position_in_samples();
 
252
    if (pbuffer_repp != 0) {
 
253
      pbuffer_repp->reset();
 
254
    }
 
255
 
 
256
    finished_rep = false;
 
257
 
 
258
    restore_db_server_state(was_running);
 
259
  }
 
260
 
 
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);
 
264
}
 
265
 
 
266
/**
 
267
 * Opens the child audio object (possibly in exclusive mode).
 
268
 * This routine is meant for opening files and devices,
 
269
 * loading libraries, etc. 
 
270
 */
 
271
void AUDIO_IO_DB_CLIENT::open(void) throw(AUDIO_IO::SETUP_ERROR&) 
 
272
{
 
273
  ECA_LOG_MSG(ECA_LOGGER::user_objects, "open " + label() + ".");
 
274
 
 
275
  if (child()->is_open() != true) {
 
276
    child()->open();
 
277
  }
 
278
 
 
279
  set_audio_format(child()->audio_format());
 
280
  set_length_in_samples(child()->length_in_samples());
 
281
 
 
282
  if (pbuffer_repp == 0) {
 
283
    pserver_repp->register_client(child());
 
284
    pbuffer_repp = pserver_repp->get_client_buffer(child());
 
285
 
 
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());
 
289
    }
 
290
 
 
291
    if (io_mode() == AUDIO_IO::io_read) 
 
292
      pbuffer_repp->io_mode_rep = AUDIO_IO::io_read;
 
293
    else
 
294
      pbuffer_repp->io_mode_rep = AUDIO_IO::io_write;
 
295
  }
 
296
 
 
297
  AUDIO_IO::open();
 
298
}
 
299
 
 
300
/**
 
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).
 
304
 */
 
305
void AUDIO_IO_DB_CLIENT::close(void)
 
306
{
 
307
  ECA_LOG_MSG(ECA_LOGGER::user_objects, "close " + label() + ".");
 
308
 
 
309
  if (child()->is_open() == true) child()->close();
 
310
 
 
311
  AUDIO_IO::close();
 
312
}
 
313
 
 
314
void AUDIO_IO_DB_CLIENT::start_io(void)
 
315
{
 
316
  AUDIO_IO_PROXY::start_io();
 
317
 
 
318
  /* note: child may have changed its position after 
 
319
   *       start_io() is issued (via AUDIO_IO_PROXY::start_io() */
 
320
 
 
321
  if (child()->supports_seeking() == true) {
 
322
    bool was_running = pause_db_server_if_running();
 
323
 
 
324
    set_position_in_samples(child()->position_in_samples());
 
325
 
 
326
    /* as position might have changed, flush the buffers */
 
327
    if (pbuffer_repp != 0) {
 
328
      pbuffer_repp->reset();
 
329
    }
 
330
 
 
331
    restore_db_server_state(was_running);
 
332
  }
 
333
}
 
334
 
 
335
void AUDIO_IO_DB_CLIENT::stop_io(void)
 
336
{
 
337
  AUDIO_IO_PROXY::stop_io();
 
338
}