~noskcaj/ubuntu/trusty/ekiga/ftbfs

« back to all changes in this revision

Viewing changes to src/devices/audio.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2006-01-28 18:49:20 UTC
  • Revision ID: james.westby@ubuntu.com-20060128184920-v525ihmiv7id40xs
Tags: upstream-1.99.0
ImportĀ upstreamĀ versionĀ 1.99.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/* GnomeMeeting -- A Video-Conferencing application
 
3
 * Copyright (C) 2000-2006 Damien Sandras
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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
 *
 
19
 *
 
20
 * GnomeMeting is licensed under the GPL license and as a special exception,
 
21
 * you have permission to link or otherwise combine this program with the
 
22
 * programs OpenH323 and Pwlib, and distribute the combination, without
 
23
 * applying the requirements of the GNU GPL to the OpenH323 program, as long
 
24
 * as you do follow the requirements of the GNU GPL for all the rest of the
 
25
 * software thus combined.
 
26
 */
 
27
 
 
28
 
 
29
/*
 
30
 *                         sound_handling.cpp  -  description
 
31
 *                         ----------------------------------
 
32
 *   begin                : Thu Nov 22 2001
 
33
 *   copyright            : (C) 2000-2006 by Damien Sandras
 
34
 *   description          : This file contains sound handling functions.
 
35
 *
 
36
 */
 
37
 
 
38
#include "../../config.h"
 
39
 
 
40
#include "common.h"
 
41
#include "ekiga.h"
 
42
#include "audio.h"
 
43
#include "manager.h"
 
44
#include "misc.h"
 
45
#include "druid.h"
 
46
 
 
47
#include "gmlevelmeter.h"
 
48
#include "gmdialog.h"
 
49
#include "gmconf.h"
 
50
 
 
51
 
 
52
#ifdef __linux__
 
53
#include <linux/soundcard.h>
 
54
#endif
 
55
 
 
56
#ifdef __FreeBSD__
 
57
#if (__FreeBSD__ >= 5)
 
58
#include <sys/soundcard.h>
 
59
#else
 
60
#include <machine/soundcard.h>
 
61
#endif
 
62
#endif
 
63
 
 
64
#include <ptclib/pwavfile.h>
 
65
#include <cmath>
 
66
 
 
67
#ifdef WIN32
 
68
#include "winpaths.h"
 
69
#endif
 
70
 
 
71
static void dialog_response_cb (GtkWidget *, gint, gpointer);
 
72
 
 
73
 
 
74
/* The GTK callbacks */
 
75
static void dialog_response_cb (GtkWidget *w, 
 
76
                                gint, 
 
77
                                gpointer data)
 
78
{
 
79
  g_return_if_fail (data);
 
80
 
 
81
 
 
82
  gm_druid_window_set_test_buttons_sensitivity (GTK_WIDGET (data), FALSE);
 
83
 
 
84
  gtk_widget_hide (w);
 
85
}
 
86
 
 
87
 
 
88
/* The functions */
 
89
void 
 
90
gnomemeeting_sound_daemons_suspend (void)
 
91
{
 
92
#ifndef DISABLE_GNOME
 
93
  int esd_client = 0;
 
94
  
 
95
  /* Put ESD into standby mode */
 
96
  esd_client = esd_open_sound (NULL);
 
97
 
 
98
  if (esd_client >= 0) {
 
99
    
 
100
    esd_standby (esd_client);
 
101
    esd_close (esd_client);
 
102
  }
 
103
#endif
 
104
}
 
105
 
 
106
 
 
107
void 
 
108
gnomemeeting_sound_daemons_resume (void)
 
109
{
 
110
#ifndef DISABLE_GNOME
 
111
  int esd_client = 0;
 
112
 
 
113
  /* Put ESD into normal mode */
 
114
  esd_client = esd_open_sound (NULL);
 
115
 
 
116
  if (esd_client >= 0) {
 
117
    
 
118
    esd_resume (esd_client);
 
119
    esd_close (esd_client);
 
120
  }
 
121
#endif
 
122
}
 
123
 
 
124
 
 
125
GMSoundEvent::GMSoundEvent (PString ev)
 
126
{
 
127
  event = ev;
 
128
 
 
129
  gnomemeeting_sound_daemons_suspend ();
 
130
  Main ();
 
131
  gnomemeeting_sound_daemons_resume ();
 
132
}
 
133
 
 
134
 
 
135
void GMSoundEvent::Main ()
 
136
{
 
137
  gchar *sound_file = NULL;
 
138
  gchar *device = NULL;
 
139
  gchar *plugin = NULL;
 
140
  gchar *filename = NULL;
 
141
 
 
142
  PSound sound;
 
143
  PSoundChannel *channel = NULL;
 
144
 
 
145
  PBYTEArray buffer;  
 
146
 
 
147
  PString psound_file;
 
148
  PString enable_event_conf_key;
 
149
  PString event_conf_key;
 
150
  PWAVFile *wav = NULL;
 
151
  
 
152
  plugin = gm_conf_get_string (AUDIO_DEVICES_KEY "plugin");
 
153
  if (event == "busy_tone_sound" || event == "ring_tone_sound")
 
154
    device = gm_conf_get_string (AUDIO_DEVICES_KEY "output_device");
 
155
  else
 
156
    device = gm_conf_get_string (SOUND_EVENTS_KEY "output_device");
 
157
 
 
158
  enable_event_conf_key = PString (SOUND_EVENTS_KEY) + "enable_" + event;
 
159
  if (event.Find ("/") == P_MAX_INDEX) {
 
160
    
 
161
    event_conf_key = PString (SOUND_EVENTS_KEY) + event;
 
162
    sound_file = gm_conf_get_string ((gchar *) (const char *) event_conf_key);
 
163
  }
 
164
  
 
165
  if (!sound_file ||
 
166
      gm_conf_get_bool ((gchar *) (const char *) enable_event_conf_key)) {
 
167
 
 
168
    if (!sound_file)    
 
169
      sound_file = g_strdup ((const char *) event);
 
170
 
 
171
    /* first assume the entry is a full path to a file */
 
172
    wav = new PWAVFile (sound_file, PFile::ReadOnly);
 
173
   
 
174
    if (!wav->IsValid ()) {
 
175
      /* it isn't a full path to a file : add our default path */
 
176
 
 
177
      delete wav;
 
178
      wav = NULL;
 
179
 
 
180
      filename = g_build_filename (DATA_DIR, "sounds", PACKAGE_NAME,
 
181
                                   sound_file, NULL);
 
182
      wav = new PWAVFile (filename, PFile::ReadOnly);
 
183
      g_free (filename);
 
184
 
 
185
    }
 
186
 
 
187
    if (wav->IsValid ()) {
 
188
      
 
189
      channel =
 
190
        PSoundChannel::CreateOpenedChannel (plugin, device,
 
191
                                            PSoundChannel::Player, 
 
192
                                            wav->GetChannels (),
 
193
                                            wav->GetSampleRate (),
 
194
                                            wav->GetSampleSize ());
 
195
    
 
196
 
 
197
      if (channel) {
 
198
 
 
199
        channel->SetBuffers (640, 2);
 
200
        
 
201
        buffer.SetSize (wav->GetDataLength ());
 
202
        memset (buffer.GetPointer (), '0', buffer.GetSize ());
 
203
        wav->Read (buffer.GetPointer (), wav->GetDataLength ());
 
204
      
 
205
        sound = buffer;
 
206
        channel->PlaySound (sound);
 
207
        channel->Close ();
 
208
    
 
209
        delete (channel);
 
210
      }
 
211
 
 
212
    }
 
213
  }
 
214
 
 
215
  delete wav;
 
216
  g_free (sound_file);
 
217
  g_free (device);
 
218
  g_free (plugin);
 
219
}
 
220
 
 
221
 
 
222
GMAudioRP::GMAudioRP (BOOL enc,
 
223
                      GMAudioTester &t)
 
224
  :PThread (1000, NoAutoDeleteThread), tester (t)
 
225
{
 
226
  is_encoding = enc;
 
227
  device_name = enc ? tester.audio_recorder:tester.audio_player;
 
228
  driver_name = tester.audio_manager;
 
229
  stop = FALSE;
 
230
 
 
231
  this->Resume ();
 
232
  thread_sync_point.Wait ();
 
233
}
 
234
 
 
235
 
 
236
GMAudioRP::~GMAudioRP ()
 
237
{
 
238
  stop = TRUE;
 
239
 
 
240
  PWaitAndSignal m(quit_mutex);
 
241
}
 
242
 
 
243
 
 
244
void GMAudioRP::Main ()
 
245
{
 
246
  GtkWidget *druid_window = NULL;
 
247
  
 
248
  PSoundChannel *channel = NULL;
 
249
  
 
250
  gchar *msg = NULL;
 
251
  char *buffer = NULL;
 
252
  
 
253
  BOOL label_displayed = FALSE;
 
254
 
 
255
  int buffer_pos = 0;
 
256
  static int nbr_opened_channels = 0;
 
257
 
 
258
  gfloat val = 0.0;
 
259
  
 
260
  PTime now;
 
261
 
 
262
  PWaitAndSignal m(quit_mutex);
 
263
  thread_sync_point.Signal ();
 
264
 
 
265
  druid_window = GnomeMeeting::Process ()->GetDruidWindow ();
 
266
    
 
267
  buffer = (char *) malloc (640);
 
268
  memset (buffer, '0', sizeof (buffer));
 
269
  
 
270
  /* We try to open the selected device */
 
271
  if (driver_name != "Quicknet") {
 
272
    channel = 
 
273
      PSoundChannel::CreateOpenedChannel (driver_name,
 
274
                                          device_name,
 
275
                                          is_encoding ?
 
276
                                          PSoundChannel::Recorder
 
277
                                          : PSoundChannel::Player,
 
278
                                          1, 8000, 16);
 
279
  }
 
280
  
 
281
  if (!is_encoding)
 
282
    msg = g_strdup_printf ("<b>%s</b>", _("Opening device for playing"));
 
283
  else
 
284
    msg = g_strdup_printf ("<b>%s</b>", _("Opening device for recording"));
 
285
 
 
286
  gdk_threads_enter ();
 
287
  gtk_label_set_markup (GTK_LABEL (tester.test_label), msg);
 
288
  gdk_threads_leave ();
 
289
  g_free (msg);
 
290
 
 
291
  if (!channel) {
 
292
 
 
293
    gdk_threads_enter ();  
 
294
    if (is_encoding)
 
295
      gnomemeeting_error_dialog (GTK_WINDOW (druid_window), _("Failed to open the device"), _("Impossible to open the selected audio device (%s) for recording. Please check your audio setup, the permissions and that the device is not busy."), (const char *) device_name);
 
296
    else
 
297
      gnomemeeting_error_dialog (GTK_WINDOW (druid_window), _("Failed to open the device"), _("Impossible to open the selected audio device (%s) for playing. Please check your audio setup, the permissions and that the device is not busy."), (const char *) device_name);
 
298
    gdk_threads_leave ();  
 
299
  }
 
300
  else {
 
301
    
 
302
    nbr_opened_channels++;
 
303
 
 
304
    channel->SetBuffers (640, 2);
 
305
    
 
306
    while (!stop) {
 
307
      
 
308
      if (is_encoding) {
 
309
 
 
310
        if (!channel->Read ((void *) buffer, 640)) {
 
311
      
 
312
          gdk_threads_enter ();  
 
313
          gnomemeeting_error_dialog (GTK_WINDOW (druid_window), _("Cannot use the audio device"), _("The selected audio device (%s) was successfully opened but it is impossible to read data from this device. Please check your audio setup."), (const char*) device_name);
 
314
          gdk_threads_leave ();  
 
315
 
 
316
          stop = TRUE;
 
317
        }
 
318
        else {
 
319
          
 
320
          if (!label_displayed) {
 
321
 
 
322
            msg =  g_strdup_printf ("<b>%s</b>", _("Recording your voice"));
 
323
 
 
324
            gdk_threads_enter ();
 
325
            gtk_label_set_markup (GTK_LABEL (tester.test_label), msg);
 
326
            if (nbr_opened_channels == 2)
 
327
              gnomemeeting_threads_dialog_show (GTK_WIDGET (tester.test_dialog));
 
328
            gdk_threads_leave ();
 
329
            g_free (msg);
 
330
 
 
331
            label_displayed = TRUE;
 
332
          }
 
333
 
 
334
 
 
335
          /* We update the VUMeter only 3 times for each sample
 
336
             of size 640, that will permit to spare some CPU cycles */
 
337
          for (int i = 0 ; i < 480 ; i = i + 160) {
 
338
            
 
339
            val = GetAverageSignalLevel ((const short *) (buffer + i), 160); 
 
340
 
 
341
            gdk_threads_enter ();
 
342
            gtk_levelmeter_set_level (GTK_LEVELMETER (tester.level_meter), val);
 
343
            gdk_threads_leave ();
 
344
          }
 
345
 
 
346
          
 
347
          tester.buffer_ring_access_mutex.Wait ();
 
348
          memcpy (&tester.buffer_ring [buffer_pos], buffer,  640); 
 
349
          tester.buffer_ring_access_mutex.Signal ();
 
350
 
 
351
          buffer_pos += 640;
 
352
        }
 
353
      }
 
354
      else {
 
355
        
 
356
        if ((PTime () - now).GetSeconds () > 3) {
 
357
        
 
358
          if (!label_displayed) {
 
359
 
 
360
            msg = g_strdup_printf ("<b>%s</b>", 
 
361
                                   _("Recording and playing back"));
 
362
 
 
363
            gdk_threads_enter ();
 
364
            gtk_label_set_markup (GTK_LABEL (tester.test_label), msg);
 
365
            if (nbr_opened_channels == 2)
 
366
              gnomemeeting_threads_dialog_show (GTK_WIDGET (tester.test_dialog));
 
367
            gdk_threads_leave ();
 
368
            g_free (msg);
 
369
 
 
370
            label_displayed = TRUE;
 
371
          }
 
372
 
 
373
          tester.buffer_ring_access_mutex.Wait ();
 
374
          memcpy (buffer, &tester.buffer_ring [buffer_pos], 640); 
 
375
          tester.buffer_ring_access_mutex.Signal ();
 
376
        
 
377
          buffer_pos += 640;
 
378
 
 
379
          if (!channel->Write ((void *) buffer, 640)) {
 
380
      
 
381
            gdk_threads_enter ();  
 
382
            gnomemeeting_error_dialog (GTK_WINDOW (druid_window), _("Cannot use the audio device"), _("The selected audio device (%s) was successfully opened but it is impossible to write data to this device. Please check your audio setup."), (const char*) device_name);
 
383
            gdk_threads_leave ();  
 
384
 
 
385
            stop = TRUE;
 
386
          }
 
387
        }
 
388
        else
 
389
          PThread::Current ()->Sleep (100);
 
390
      }
 
391
 
 
392
      if (buffer_pos >= 80000)
 
393
        buffer_pos = 0; 
 
394
    }
 
395
  }
 
396
 
 
397
  if (channel) {
 
398
 
 
399
    channel->Close ();
 
400
    delete (channel);
 
401
  }
 
402
  
 
403
  if (nbr_opened_channels > 0) nbr_opened_channels--;
 
404
 
 
405
  free (buffer);
 
406
}
 
407
 
 
408
 
 
409
gfloat
 
410
GMAudioRP::GetAverageSignalLevel (const short *buffer, int size)
 
411
{
 
412
  int sum = 0;
 
413
  
 
414
  const short * pcm = NULL;
 
415
  const short * end = NULL;
 
416
 
 
417
  pcm = (const short *) buffer;
 
418
  end = (const short *) (pcm + size);
 
419
  
 
420
  while (pcm != end) {
 
421
 
 
422
    if (*pcm < 0)
 
423
      sum -= *pcm++;
 
424
    else
 
425
      sum += *pcm++;
 
426
  }
 
427
          
 
428
  return log10 (9.0*sum/size/32767+1)*1.0;
 
429
}
 
430
 
 
431
 
 
432
/* The Audio tester class */
 
433
  GMAudioTester::GMAudioTester (gchar *m,
 
434
                                gchar *p,
 
435
                                gchar *r,
 
436
                                GMManager & endpoint)
 
437
  :PThread (1000, NoAutoDeleteThread), ep (endpoint)
 
438
{
 
439
  stop = FALSE;
 
440
 
 
441
  test_dialog = NULL;
 
442
  test_label = NULL;
 
443
  
 
444
  if (m)
 
445
    audio_manager = PString (m);
 
446
  if (p)
 
447
    audio_player = PString (p);
 
448
  if (r)
 
449
    audio_recorder = PString (r);
 
450
  
 
451
  this->Resume ();
 
452
  thread_sync_point.Wait ();
 
453
}
 
454
 
 
455
 
 
456
GMAudioTester::~GMAudioTester ()
 
457
{
 
458
  stop = 1;
 
459
  PWaitAndSignal m(quit_mutex);
 
460
}
 
461
 
 
462
 
 
463
void GMAudioTester::Main ()
 
464
{
 
465
  GtkWidget *druid_window = NULL;
 
466
  
 
467
  GMAudioRP *player = NULL;
 
468
  GMAudioRP *recorder = NULL;
 
469
 
 
470
  gchar *msg = NULL;
 
471
 
 
472
  druid_window = GnomeMeeting::Process ()->GetDruidWindow ();
 
473
 
 
474
 
 
475
  PWaitAndSignal m(quit_mutex);
 
476
  thread_sync_point.Signal ();
 
477
 
 
478
  if (audio_manager.IsEmpty ()
 
479
      || audio_recorder.IsEmpty ()
 
480
      || audio_player.IsEmpty ()
 
481
      || audio_recorder == PString (_("No device found"))
 
482
      || audio_player == PString (_("No device found")))
 
483
    return;
 
484
 
 
485
  gnomemeeting_sound_daemons_suspend ();
 
486
  
 
487
  buffer_ring = (char *) malloc (8000 /*Hz*/ * 5 /*s*/ * 2 /*16bits*/);
 
488
 
 
489
  memset (buffer_ring, '0', sizeof (buffer_ring));
 
490
 
 
491
  gdk_threads_enter ();
 
492
  test_dialog =
 
493
    gtk_dialog_new_with_buttons ("Audio test running",
 
494
                                 GTK_WINDOW (druid_window),
 
495
                                 (GtkDialogFlags) (GTK_DIALOG_MODAL),
 
496
                                 GTK_STOCK_OK,
 
497
                                 GTK_RESPONSE_ACCEPT,
 
498
                                 NULL);
 
499
  msg = 
 
500
    g_strdup_printf (_("Ekiga is now recording from %s and playing back to %s. Please say \"1, 2, 3, Ekiga rocks!\" in your microphone. You should hear yourself back into the speakers with a four-second delay."), (const char *) audio_recorder, (const char *) audio_player);
 
501
  test_label = gtk_label_new (msg);
 
502
  gtk_label_set_line_wrap (GTK_LABEL (test_label), true);
 
503
  g_free (msg);
 
504
 
 
505
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (test_dialog)->vbox), test_label,
 
506
                      FALSE, FALSE, 2);
 
507
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (test_dialog)->vbox), 
 
508
                      gtk_hseparator_new (), FALSE, FALSE, 2);
 
509
 
 
510
  test_label = gtk_label_new (NULL);
 
511
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (test_dialog)->vbox), 
 
512
                      test_label, FALSE, FALSE, 2);
 
513
 
 
514
  level_meter = gtk_levelmeter_new ();
 
515
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (test_dialog)->vbox), 
 
516
                      level_meter, FALSE, FALSE, 2);
 
517
    
 
518
  g_signal_connect (G_OBJECT (test_dialog), "delete-event",
 
519
                    G_CALLBACK (gtk_widget_hide_on_delete), NULL);
 
520
  g_signal_connect (G_OBJECT (test_dialog), "response",
 
521
                    G_CALLBACK (dialog_response_cb), 
 
522
                    druid_window);
 
523
 
 
524
  gtk_window_set_transient_for (GTK_WINDOW (test_dialog),
 
525
                                GTK_WINDOW (druid_window));
 
526
  gtk_widget_show_all (GTK_DIALOG (test_dialog)->vbox);
 
527
  gdk_threads_leave ();
 
528
 
 
529
  recorder = new GMAudioRP (TRUE, *this);
 
530
  player = new GMAudioRP (FALSE, *this);
 
531
 
 
532
  
 
533
  while (!stop && !player->IsTerminated () && !recorder->IsTerminated ()) {
 
534
 
 
535
    PThread::Current ()->Sleep (100);
 
536
  }
 
537
 
 
538
  delete (player);
 
539
  delete (recorder);
 
540
 
 
541
  gdk_threads_enter ();
 
542
  if (test_dialog)
 
543
    gnomemeeting_threads_widget_destroy (test_dialog);
 
544
  gdk_threads_leave ();
 
545
 
 
546
  gnomemeeting_sound_daemons_resume ();
 
547
  
 
548
  free (buffer_ring);
 
549
}