From patchwork Mon Jun 1 13:23:39 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?UTF-8?B?Wm9sdMOhbiBLxZF2w6Fnw7M=?= X-Patchwork-Id: 479033 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41028140E61 for ; Mon, 1 Jun 2015 23:24:56 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=daCtqIH5; dkim-atps=neutral Received: from localhost ([::1]:52484 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YzPi2-0003tv-BV for incoming@patchwork.ozlabs.org; Mon, 01 Jun 2015 09:24:54 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:54193) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YzPhN-0002mI-8H for qemu-devel@nongnu.org; Mon, 01 Jun 2015 09:24:15 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YzPhJ-0007gT-SB for qemu-devel@nongnu.org; Mon, 01 Jun 2015 09:24:13 -0400 Received: from mail-wi0-x234.google.com ([2a00:1450:400c:c05::234]:32901) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YzPhJ-0007gE-I5 for qemu-devel@nongnu.org; Mon, 01 Jun 2015 09:24:09 -0400 Received: by wicmx19 with SMTP id mx19so70840124wic.0 for ; Mon, 01 Jun 2015 06:24:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; bh=9cR6tD9wufJrHocHZjyfsvRzUBsk7RaXLj/qiFmK9lo=; b=daCtqIH5ORf4hlPVHfcgOrJcvUEr7BOa5psZTYQw6ubMJ3sM5pLI5GCibgE61uv5NP pqHnhk6baUsKxv3Xt/zD+6b+uE0m/J3t5prv2ZeXa0wpnt0+btpSlI8fSJ7l0fPndLWf vYh356pkiBuC1UUaQXomxYej82zTRf0XviRsDDQv3D1ClXHpPpwRHI3LyBLcFtYoQ4dQ U3FSAv/niRFtnCmt6Ozq3VSAh72a1tyHcjiPTfjdjE5FLxbvwe6dtxRTxx0ndFfoSySk BisICysHECNdeZ4FXW2Q/iFuuvee3Sp0QWH7N03wxl8gHfa9TceREGOcx6/dphwCJ000 KelA== X-Received: by 10.180.9.7 with SMTP id v7mr12527781wia.60.1433165048907; Mon, 01 Jun 2015 06:24:08 -0700 (PDT) Received: from nullptr.home.dirty-ice.org (212-40-90-210.pool.digikabel.hu. [212.40.90.210]) by mx.google.com with ESMTPSA id js3sm21917842wjc.5.2015.06.01.06.24.07 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 01 Jun 2015 06:24:08 -0700 (PDT) From: "=?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?=" X-Google-Original-From: =?UTF-8?q?K=C5=91v=C3=A1g=C3=B3=2C=20Zolt=C3=A1n?= To: qemu-devel@nongnu.org Date: Mon, 1 Jun 2015 15:23:39 +0200 Message-Id: X-Mailer: git-send-email 2.4.2 In-Reply-To: References: MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2a00:1450:400c:c05::234 Cc: Gerd Hoffmann Subject: [Qemu-devel] [PATCH 01/12] audio: remove esd backend X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org ESD is no longer developed and replaced by PulseAudio. Signed-off-by: Kővágó, Zoltán --- audio/Makefile.objs | 1 - audio/audio_int.h | 1 - audio/esdaudio.c | 557 ---------------------------------------------------- configure | 18 +- 4 files changed, 6 insertions(+), 571 deletions(-) delete mode 100644 audio/esdaudio.c diff --git a/audio/Makefile.objs b/audio/Makefile.objs index 26a0ac9..5573ac1 100644 --- a/audio/Makefile.objs +++ b/audio/Makefile.objs @@ -6,7 +6,6 @@ common-obj-$(CONFIG_COREAUDIO) += coreaudio.o common-obj-$(CONFIG_ALSA) += alsaaudio.o common-obj-$(CONFIG_DSOUND) += dsoundaudio.o common-obj-$(CONFIG_FMOD) += fmodaudio.o -common-obj-$(CONFIG_ESD) += esdaudio.o common-obj-$(CONFIG_PA) += paaudio.o common-obj-$(CONFIG_WINWAVE) += winwaveaudio.o common-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o diff --git a/audio/audio_int.h b/audio/audio_int.h index fd019a0..9dd6b7f 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -210,7 +210,6 @@ extern struct audio_driver fmod_audio_driver; extern struct audio_driver alsa_audio_driver; extern struct audio_driver coreaudio_audio_driver; extern struct audio_driver dsound_audio_driver; -extern struct audio_driver esd_audio_driver; extern struct audio_driver pa_audio_driver; extern struct audio_driver spice_audio_driver; extern struct audio_driver winwave_audio_driver; diff --git a/audio/esdaudio.c b/audio/esdaudio.c deleted file mode 100644 index eea9cce..0000000 --- a/audio/esdaudio.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * QEMU ESD audio driver - * - * Copyright (c) 2006 Frederick Reeve (brushed up by malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include -#include "qemu-common.h" -#include "audio.h" - -#define AUDIO_CAP "esd" -#include "audio_int.h" -#include "audio_pt_int.h" - -typedef struct { - HWVoiceOut hw; - int done; - int live; - int decr; - int rpos; - void *pcm_buf; - int fd; - struct audio_pt pt; -} ESDVoiceOut; - -typedef struct { - HWVoiceIn hw; - int done; - int dead; - int incr; - int wpos; - void *pcm_buf; - int fd; - struct audio_pt pt; -} ESDVoiceIn; - -static struct { - int samples; - int divisor; - char *dac_host; - char *adc_host; -} conf = { - .samples = 1024, - .divisor = 2, -}; - -static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); - - AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); -} - -/* playback */ -static void *qesd_thread_out (void *arg) -{ - ESDVoiceOut *esd = arg; - HWVoiceOut *hw = &esd->hw; - int threshold; - - threshold = conf.divisor ? hw->samples / conf.divisor : 0; - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - return NULL; - } - - for (;;) { - int decr, to_mix, rpos; - - for (;;) { - if (esd->done) { - goto exit; - } - - if (esd->live > threshold) { - break; - } - - if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) { - goto exit; - } - } - - decr = to_mix = esd->live; - rpos = hw->rpos; - - if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) { - return NULL; - } - - while (to_mix) { - ssize_t written; - int chunk = audio_MIN (to_mix, hw->samples - rpos); - struct st_sample *src = hw->mix_buf + rpos; - - hw->clip (esd->pcm_buf, src, chunk); - - again: - written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift); - if (written == -1) { - if (errno == EINTR || errno == EAGAIN) { - goto again; - } - qesd_logerr (errno, "write failed\n"); - return NULL; - } - - if (written != chunk << hw->info.shift) { - int wsamples = written >> hw->info.shift; - int wbytes = wsamples << hw->info.shift; - if (wbytes != written) { - dolog ("warning: Misaligned write %d (requested %zd), " - "alignment %d\n", - wbytes, written, hw->info.align + 1); - } - to_mix -= wsamples; - rpos = (rpos + wsamples) % hw->samples; - break; - } - - rpos = (rpos + chunk) % hw->samples; - to_mix -= chunk; - } - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - return NULL; - } - - esd->rpos = rpos; - esd->live -= decr; - esd->decr += decr; - } - - exit: - audio_pt_unlock (&esd->pt, AUDIO_FUNC); - return NULL; -} - -static int qesd_run_out (HWVoiceOut *hw, int live) -{ - int decr; - ESDVoiceOut *esd = (ESDVoiceOut *) hw; - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - return 0; - } - - decr = audio_MIN (live, esd->decr); - esd->decr -= decr; - esd->live = live - decr; - hw->rpos = esd->rpos; - if (esd->live > 0) { - audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); - } - else { - audio_pt_unlock (&esd->pt, AUDIO_FUNC); - } - return decr; -} - -static int qesd_write (SWVoiceOut *sw, void *buf, int len) -{ - return audio_pcm_sw_write (sw, buf, len); -} - -static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as) -{ - ESDVoiceOut *esd = (ESDVoiceOut *) hw; - struct audsettings obt_as = *as; - int esdfmt = ESD_STREAM | ESD_PLAY; - - esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO; - switch (as->fmt) { - case AUD_FMT_S8: - case AUD_FMT_U8: - esdfmt |= ESD_BITS8; - obt_as.fmt = AUD_FMT_U8; - break; - - case AUD_FMT_S32: - case AUD_FMT_U32: - dolog ("Will use 16 instead of 32 bit samples\n"); - /* fall through */ - case AUD_FMT_S16: - case AUD_FMT_U16: - deffmt: - esdfmt |= ESD_BITS16; - obt_as.fmt = AUD_FMT_S16; - break; - - default: - dolog ("Internal logic error: Bad audio format %d\n", as->fmt); - goto deffmt; - - } - obt_as.endianness = AUDIO_HOST_ENDIANNESS; - - audio_pcm_init_info (&hw->info, &obt_as); - - hw->samples = conf.samples; - esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - if (!esd->pcm_buf) { - dolog ("Could not allocate buffer (%d bytes)\n", - hw->samples << hw->info.shift); - return -1; - } - - esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL); - if (esd->fd < 0) { - qesd_logerr (errno, "esd_play_stream failed\n"); - goto fail1; - } - - if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) { - goto fail2; - } - - return 0; - - fail2: - if (close (esd->fd)) { - qesd_logerr (errno, "%s: close on esd socket(%d) failed\n", - AUDIO_FUNC, esd->fd); - } - esd->fd = -1; - - fail1: - g_free (esd->pcm_buf); - esd->pcm_buf = NULL; - return -1; -} - -static void qesd_fini_out (HWVoiceOut *hw) -{ - void *ret; - ESDVoiceOut *esd = (ESDVoiceOut *) hw; - - audio_pt_lock (&esd->pt, AUDIO_FUNC); - esd->done = 1; - audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); - audio_pt_join (&esd->pt, &ret, AUDIO_FUNC); - - if (esd->fd >= 0) { - if (close (esd->fd)) { - qesd_logerr (errno, "failed to close esd socket\n"); - } - esd->fd = -1; - } - - audio_pt_fini (&esd->pt, AUDIO_FUNC); - - g_free (esd->pcm_buf); - esd->pcm_buf = NULL; -} - -static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - (void) hw; - (void) cmd; - return 0; -} - -/* capture */ -static void *qesd_thread_in (void *arg) -{ - ESDVoiceIn *esd = arg; - HWVoiceIn *hw = &esd->hw; - int threshold; - - threshold = conf.divisor ? hw->samples / conf.divisor : 0; - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - return NULL; - } - - for (;;) { - int incr, to_grab, wpos; - - for (;;) { - if (esd->done) { - goto exit; - } - - if (esd->dead > threshold) { - break; - } - - if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) { - goto exit; - } - } - - incr = to_grab = esd->dead; - wpos = hw->wpos; - - if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) { - return NULL; - } - - while (to_grab) { - ssize_t nread; - int chunk = audio_MIN (to_grab, hw->samples - wpos); - void *buf = advance (esd->pcm_buf, wpos); - - again: - nread = read (esd->fd, buf, chunk << hw->info.shift); - if (nread == -1) { - if (errno == EINTR || errno == EAGAIN) { - goto again; - } - qesd_logerr (errno, "read failed\n"); - return NULL; - } - - if (nread != chunk << hw->info.shift) { - int rsamples = nread >> hw->info.shift; - int rbytes = rsamples << hw->info.shift; - if (rbytes != nread) { - dolog ("warning: Misaligned write %d (requested %zd), " - "alignment %d\n", - rbytes, nread, hw->info.align + 1); - } - to_grab -= rsamples; - wpos = (wpos + rsamples) % hw->samples; - break; - } - - hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift); - wpos = (wpos + chunk) % hw->samples; - to_grab -= chunk; - } - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - return NULL; - } - - esd->wpos = wpos; - esd->dead -= incr; - esd->incr += incr; - } - - exit: - audio_pt_unlock (&esd->pt, AUDIO_FUNC); - return NULL; -} - -static int qesd_run_in (HWVoiceIn *hw) -{ - int live, incr, dead; - ESDVoiceIn *esd = (ESDVoiceIn *) hw; - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - return 0; - } - - live = audio_pcm_hw_get_live_in (hw); - dead = hw->samples - live; - incr = audio_MIN (dead, esd->incr); - esd->incr -= incr; - esd->dead = dead - incr; - hw->wpos = esd->wpos; - if (esd->dead > 0) { - audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); - } - else { - audio_pt_unlock (&esd->pt, AUDIO_FUNC); - } - return incr; -} - -static int qesd_read (SWVoiceIn *sw, void *buf, int len) -{ - return audio_pcm_sw_read (sw, buf, len); -} - -static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as) -{ - ESDVoiceIn *esd = (ESDVoiceIn *) hw; - struct audsettings obt_as = *as; - int esdfmt = ESD_STREAM | ESD_RECORD; - - esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO; - switch (as->fmt) { - case AUD_FMT_S8: - case AUD_FMT_U8: - esdfmt |= ESD_BITS8; - obt_as.fmt = AUD_FMT_U8; - break; - - case AUD_FMT_S16: - case AUD_FMT_U16: - esdfmt |= ESD_BITS16; - obt_as.fmt = AUD_FMT_S16; - break; - - case AUD_FMT_S32: - case AUD_FMT_U32: - dolog ("Will use 16 instead of 32 bit samples\n"); - esdfmt |= ESD_BITS16; - obt_as.fmt = AUD_FMT_S16; - break; - } - obt_as.endianness = AUDIO_HOST_ENDIANNESS; - - audio_pcm_init_info (&hw->info, &obt_as); - - hw->samples = conf.samples; - esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - if (!esd->pcm_buf) { - dolog ("Could not allocate buffer (%d bytes)\n", - hw->samples << hw->info.shift); - return -1; - } - - esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL); - if (esd->fd < 0) { - qesd_logerr (errno, "esd_record_stream failed\n"); - goto fail1; - } - - if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) { - goto fail2; - } - - return 0; - - fail2: - if (close (esd->fd)) { - qesd_logerr (errno, "%s: close on esd socket(%d) failed\n", - AUDIO_FUNC, esd->fd); - } - esd->fd = -1; - - fail1: - g_free (esd->pcm_buf); - esd->pcm_buf = NULL; - return -1; -} - -static void qesd_fini_in (HWVoiceIn *hw) -{ - void *ret; - ESDVoiceIn *esd = (ESDVoiceIn *) hw; - - audio_pt_lock (&esd->pt, AUDIO_FUNC); - esd->done = 1; - audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); - audio_pt_join (&esd->pt, &ret, AUDIO_FUNC); - - if (esd->fd >= 0) { - if (close (esd->fd)) { - qesd_logerr (errno, "failed to close esd socket\n"); - } - esd->fd = -1; - } - - audio_pt_fini (&esd->pt, AUDIO_FUNC); - - g_free (esd->pcm_buf); - esd->pcm_buf = NULL; -} - -static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...) -{ - (void) hw; - (void) cmd; - return 0; -} - -/* common */ -static void *qesd_audio_init (void) -{ - return &conf; -} - -static void qesd_audio_fini (void *opaque) -{ - (void) opaque; - ldebug ("esd_fini"); -} - -struct audio_option qesd_options[] = { - { - .name = "SAMPLES", - .tag = AUD_OPT_INT, - .valp = &conf.samples, - .descr = "buffer size in samples" - }, - { - .name = "DIVISOR", - .tag = AUD_OPT_INT, - .valp = &conf.divisor, - .descr = "threshold divisor" - }, - { - .name = "DAC_HOST", - .tag = AUD_OPT_STR, - .valp = &conf.dac_host, - .descr = "playback host" - }, - { - .name = "ADC_HOST", - .tag = AUD_OPT_STR, - .valp = &conf.adc_host, - .descr = "capture host" - }, - { /* End of list */ } -}; - -static struct audio_pcm_ops qesd_pcm_ops = { - .init_out = qesd_init_out, - .fini_out = qesd_fini_out, - .run_out = qesd_run_out, - .write = qesd_write, - .ctl_out = qesd_ctl_out, - - .init_in = qesd_init_in, - .fini_in = qesd_fini_in, - .run_in = qesd_run_in, - .read = qesd_read, - .ctl_in = qesd_ctl_in, -}; - -struct audio_driver esd_audio_driver = { - .name = "esd", - .descr = "http://en.wikipedia.org/wiki/Esound", - .options = qesd_options, - .init = qesd_audio_init, - .fini = qesd_audio_fini, - .pcm_ops = &qesd_pcm_ops, - .can_be_default = 0, - .max_voices_out = INT_MAX, - .max_voices_in = INT_MAX, - .voice_size_out = sizeof (ESDVoiceOut), - .voice_size_in = sizeof (ESDVoiceIn) -}; diff --git a/configure b/configure index 4e2f78a..acd471d 100755 --- a/configure +++ b/configure @@ -575,13 +575,13 @@ MINGW32*) GNU/kFreeBSD) bsd="yes" audio_drv_list="oss" - audio_possible_drivers="oss sdl esd pa" + audio_possible_drivers="oss sdl pa" ;; FreeBSD) bsd="yes" make="${MAKE-gmake}" audio_drv_list="oss" - audio_possible_drivers="oss sdl esd pa" + audio_possible_drivers="oss sdl pa" # needed for kinfo_getvmmap(3) in libutil.h LIBS="-lutil $LIBS" netmap="" # enable netmap autodetect @@ -591,14 +591,14 @@ DragonFly) bsd="yes" make="${MAKE-gmake}" audio_drv_list="oss" - audio_possible_drivers="oss sdl esd pa" + audio_possible_drivers="oss sdl pa" HOST_VARIANT_DIR="dragonfly" ;; NetBSD) bsd="yes" make="${MAKE-gmake}" audio_drv_list="oss" - audio_possible_drivers="oss sdl esd" + audio_possible_drivers="oss sdl" oss_lib="-lossaudio" HOST_VARIANT_DIR="netbsd" ;; @@ -606,7 +606,7 @@ OpenBSD) bsd="yes" make="${MAKE-gmake}" audio_drv_list="sdl" - audio_possible_drivers="sdl esd" + audio_possible_drivers="sdl" HOST_VARIANT_DIR="openbsd" ;; Darwin) @@ -674,7 +674,7 @@ Haiku) ;; *) audio_drv_list="oss" - audio_possible_drivers="oss alsa sdl esd pa" + audio_possible_drivers="oss alsa sdl pa" linux="yes" linux_user="yes" kvm="yes" @@ -2630,12 +2630,6 @@ for drv in $audio_drv_list; do libs_softmmu="$fmod_lib $libs_softmmu" ;; - esd) - audio_drv_probe $drv esd.h -lesd 'return esd_play_stream(0, 0, "", 0);' - libs_softmmu="-lesd $libs_softmmu" - audio_pt_int="yes" - ;; - pa) audio_drv_probe $drv pulse/mainloop.h "-lpulse" \ "pa_mainloop *m = 0; pa_mainloop_free (m); return 0;"