2
/* GnomeMeeting -- A Video-Conferencing application
3
* Copyright (C) 2000-2006 Damien Sandras
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.
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.
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.
38
#include "../../config.h"
47
#include "gmlevelmeter.h"
53
#include <linux/soundcard.h>
57
#if (__FreeBSD__ >= 5)
58
#include <sys/soundcard.h>
60
#include <machine/soundcard.h>
64
#include <ptclib/pwavfile.h>
71
static void dialog_response_cb (GtkWidget *, gint, gpointer);
74
/* The GTK callbacks */
75
static void dialog_response_cb (GtkWidget *w,
79
g_return_if_fail (data);
82
gm_druid_window_set_test_buttons_sensitivity (GTK_WIDGET (data), FALSE);
90
gnomemeeting_sound_daemons_suspend (void)
95
/* Put ESD into standby mode */
96
esd_client = esd_open_sound (NULL);
98
if (esd_client >= 0) {
100
esd_standby (esd_client);
101
esd_close (esd_client);
108
gnomemeeting_sound_daemons_resume (void)
110
#ifndef DISABLE_GNOME
113
/* Put ESD into normal mode */
114
esd_client = esd_open_sound (NULL);
116
if (esd_client >= 0) {
118
esd_resume (esd_client);
119
esd_close (esd_client);
125
GMSoundEvent::GMSoundEvent (PString ev)
129
gnomemeeting_sound_daemons_suspend ();
131
gnomemeeting_sound_daemons_resume ();
135
void GMSoundEvent::Main ()
137
gchar *sound_file = NULL;
138
gchar *device = NULL;
139
gchar *plugin = NULL;
140
gchar *filename = NULL;
143
PSoundChannel *channel = NULL;
148
PString enable_event_conf_key;
149
PString event_conf_key;
150
PWAVFile *wav = NULL;
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");
156
device = gm_conf_get_string (SOUND_EVENTS_KEY "output_device");
158
enable_event_conf_key = PString (SOUND_EVENTS_KEY) + "enable_" + event;
159
if (event.Find ("/") == P_MAX_INDEX) {
161
event_conf_key = PString (SOUND_EVENTS_KEY) + event;
162
sound_file = gm_conf_get_string ((gchar *) (const char *) event_conf_key);
166
gm_conf_get_bool ((gchar *) (const char *) enable_event_conf_key)) {
169
sound_file = g_strdup ((const char *) event);
171
/* first assume the entry is a full path to a file */
172
wav = new PWAVFile (sound_file, PFile::ReadOnly);
174
if (!wav->IsValid ()) {
175
/* it isn't a full path to a file : add our default path */
180
filename = g_build_filename (DATA_DIR, "sounds", PACKAGE_NAME,
182
wav = new PWAVFile (filename, PFile::ReadOnly);
187
if (wav->IsValid ()) {
190
PSoundChannel::CreateOpenedChannel (plugin, device,
191
PSoundChannel::Player,
193
wav->GetSampleRate (),
194
wav->GetSampleSize ());
199
channel->SetBuffers (640, 2);
201
buffer.SetSize (wav->GetDataLength ());
202
memset (buffer.GetPointer (), '0', buffer.GetSize ());
203
wav->Read (buffer.GetPointer (), wav->GetDataLength ());
206
channel->PlaySound (sound);
222
GMAudioRP::GMAudioRP (BOOL enc,
224
:PThread (1000, NoAutoDeleteThread), tester (t)
227
device_name = enc ? tester.audio_recorder:tester.audio_player;
228
driver_name = tester.audio_manager;
232
thread_sync_point.Wait ();
236
GMAudioRP::~GMAudioRP ()
240
PWaitAndSignal m(quit_mutex);
244
void GMAudioRP::Main ()
246
GtkWidget *druid_window = NULL;
248
PSoundChannel *channel = NULL;
253
BOOL label_displayed = FALSE;
256
static int nbr_opened_channels = 0;
262
PWaitAndSignal m(quit_mutex);
263
thread_sync_point.Signal ();
265
druid_window = GnomeMeeting::Process ()->GetDruidWindow ();
267
buffer = (char *) malloc (640);
268
memset (buffer, '0', sizeof (buffer));
270
/* We try to open the selected device */
271
if (driver_name != "Quicknet") {
273
PSoundChannel::CreateOpenedChannel (driver_name,
276
PSoundChannel::Recorder
277
: PSoundChannel::Player,
282
msg = g_strdup_printf ("<b>%s</b>", _("Opening device for playing"));
284
msg = g_strdup_printf ("<b>%s</b>", _("Opening device for recording"));
286
gdk_threads_enter ();
287
gtk_label_set_markup (GTK_LABEL (tester.test_label), msg);
288
gdk_threads_leave ();
293
gdk_threads_enter ();
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);
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 ();
302
nbr_opened_channels++;
304
channel->SetBuffers (640, 2);
310
if (!channel->Read ((void *) buffer, 640)) {
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 ();
320
if (!label_displayed) {
322
msg = g_strdup_printf ("<b>%s</b>", _("Recording your voice"));
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 ();
331
label_displayed = TRUE;
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) {
339
val = GetAverageSignalLevel ((const short *) (buffer + i), 160);
341
gdk_threads_enter ();
342
gtk_levelmeter_set_level (GTK_LEVELMETER (tester.level_meter), val);
343
gdk_threads_leave ();
347
tester.buffer_ring_access_mutex.Wait ();
348
memcpy (&tester.buffer_ring [buffer_pos], buffer, 640);
349
tester.buffer_ring_access_mutex.Signal ();
356
if ((PTime () - now).GetSeconds () > 3) {
358
if (!label_displayed) {
360
msg = g_strdup_printf ("<b>%s</b>",
361
_("Recording and playing back"));
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 ();
370
label_displayed = TRUE;
373
tester.buffer_ring_access_mutex.Wait ();
374
memcpy (buffer, &tester.buffer_ring [buffer_pos], 640);
375
tester.buffer_ring_access_mutex.Signal ();
379
if (!channel->Write ((void *) buffer, 640)) {
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 ();
389
PThread::Current ()->Sleep (100);
392
if (buffer_pos >= 80000)
403
if (nbr_opened_channels > 0) nbr_opened_channels--;
410
GMAudioRP::GetAverageSignalLevel (const short *buffer, int size)
414
const short * pcm = NULL;
415
const short * end = NULL;
417
pcm = (const short *) buffer;
418
end = (const short *) (pcm + size);
428
return log10 (9.0*sum/size/32767+1)*1.0;
432
/* The Audio tester class */
433
GMAudioTester::GMAudioTester (gchar *m,
436
GMManager & endpoint)
437
:PThread (1000, NoAutoDeleteThread), ep (endpoint)
445
audio_manager = PString (m);
447
audio_player = PString (p);
449
audio_recorder = PString (r);
452
thread_sync_point.Wait ();
456
GMAudioTester::~GMAudioTester ()
459
PWaitAndSignal m(quit_mutex);
463
void GMAudioTester::Main ()
465
GtkWidget *druid_window = NULL;
467
GMAudioRP *player = NULL;
468
GMAudioRP *recorder = NULL;
472
druid_window = GnomeMeeting::Process ()->GetDruidWindow ();
475
PWaitAndSignal m(quit_mutex);
476
thread_sync_point.Signal ();
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")))
485
gnomemeeting_sound_daemons_suspend ();
487
buffer_ring = (char *) malloc (8000 /*Hz*/ * 5 /*s*/ * 2 /*16bits*/);
489
memset (buffer_ring, '0', sizeof (buffer_ring));
491
gdk_threads_enter ();
493
gtk_dialog_new_with_buttons ("Audio test running",
494
GTK_WINDOW (druid_window),
495
(GtkDialogFlags) (GTK_DIALOG_MODAL),
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);
505
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (test_dialog)->vbox), test_label,
507
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (test_dialog)->vbox),
508
gtk_hseparator_new (), FALSE, FALSE, 2);
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);
514
level_meter = gtk_levelmeter_new ();
515
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (test_dialog)->vbox),
516
level_meter, FALSE, FALSE, 2);
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),
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 ();
529
recorder = new GMAudioRP (TRUE, *this);
530
player = new GMAudioRP (FALSE, *this);
533
while (!stop && !player->IsTerminated () && !recorder->IsTerminated ()) {
535
PThread::Current ()->Sleep (100);
541
gdk_threads_enter ();
543
gnomemeeting_threads_widget_destroy (test_dialog);
544
gdk_threads_leave ();
546
gnomemeeting_sound_daemons_resume ();