<commit_before>/*
 * Copyright (C) 2010 Nokia Corporation.
 *
 * Contact: <NAME> <<EMAIL>>
 *          or <NAME> <<EMAIL>>
 *
 * These PulseAudio Modules are free software; you can redistribute
 * it and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation
 * version 2.1 of the License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 * USA.
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <assert.h>
#include <math.h>

#include <pulse/xmalloc.h>

#include <pulsecore/sink-input.h>
#include <pulsecore/source-output.h>
#include <pulsecore/module.h>
#include <pulsecore/modargs.h>
#include <pulsecore/namereg.h>
#include <pulsecore/log.h>
#include <pulsecore/mutex.h>
#include <pulsecore/atomic.h>
#include <pulsecore/semaphore.h>
#include <pulsecore/thread.h>
#include <pulsecore/sample-util.h>

#include "module-voice-userdata.h"
#include "voice-hw-sink-input.h"
#include "voice-util.h"
#include "voice-voip-sink.h"
#include "voice-raw-sink.h"
#include "voice-aep-ear-ref.h"
#include "voice-convert.h"
#include "pa-optimized.h"
#include "optimized.h"
#include "memory.h"
#include "voice-voip-source.h"

#include "module-voice-api.h"
#include "voice-hooks.h"

static unsigned int voice_dl_sideinfo_pop(struct userdata *u, int length) {
    unsigned int spc_flags = 0;

    pa_assert(u);
    pa_assert(length % u->aep_fragment_size == 0);

    while (length) {
        spc_flags = (unsigned int)pa_queue_pop(u->dl_sideinfo_queue);
        length -= u->aep_fragment_size;
    }

    return spc_flags & ~VOICE_SIDEINFO_FLAG_BOGUS;
}

/* Called from IO thread context. */
static void voice_aep_sink_process(struct userdata *u, pa_memchunk *chunk) {
    unsigned int spc_flags = 0;

    pa_assert(u);

    /*
     * note: HOOK_AEP_DOWNLINK must be called even if chunk is silent
     *       to ensure proper handling of SPEECH->DTX transitions
     */

    if (voice_voip_sink_active_iothread(u)) {
        aep_downlink params;

        pa_sink_render_full(u->voip_sink, u->aep_fragment_size, chunk);
        spc_flags = voice_dl_sideinfo_pop(u, u->aep_fragment_size);

        params.chunk = chunk;
        params.spc_flags = spc_flags;
        /* TODO: get rid of cmt boolean */
        params.cmt = TRUE;

        /* TODO: I think this should be called from behind the hook */
        pa_memchunk_make_writable(chunk, u->aep_fragment_size);

        meego_algorithm_hook_fire(u->hooks[HOOK_AEP_DOWNLINK], &params);
    }
    else {
        pa_silence_memchunk_get(&u->core->silence_cache,
                                u->core->mempool,
                                chunk,
                                &u->aep_sample_spec,
                                u->aep_fragment_size);
    }
}

/*** sink_input callbacks ***/
static int hw_sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
    struct userdata *u;
    meego_algorithm_hook_data hook_data;
    pa_memchunk aepchunk = { 0, 0, 0 };
    pa_memchunk rawchunk = { 0, 0, 0 };
    pa_volume_t aep_volume = PA_VOLUME_NORM;

    pa_assert(i);
    pa_sink_input_assert_ref(i);
    pa_assert_se(u = i->userdata);
    pa_assert(chunk);

#ifdef SINK_TIMING_DEBUG_ON
    static struct timeval tv_last = { 0, 0 };
    struct timeval tv_new;
    pa_rtclock_get(&tv_new);
    pa_usec_t ched_period = pa_timeval_diff(&tv_last, &tv_new);
    tv_last = tv_new;
#endif

    /* We only operate with N * u->hw_fragment_size chunks. */
    if (length > u->hw_fragment_size_max)
        length = u->hw_fragment_size_max;
    else if (0 != (length % u->hw_fragment_size)) {
        if (voice_voip_sink_active_iothread(u)) {
            pa_silence_memchunk_get(&u->core->silence_cache,
                    u->core->mempool,
                    chunk,
                    &u->hw_sample_spec,
                    length);
                    voice_aep_ear_ref_loop_reset(u);
            return;
        }
        else
            length += u->hw_fragment_size - (length % u->hw_fragment_size);
    }

    if (u->aep_sink_input && PA_SINK_INPUT_IS_LINKED(
            u->aep_sink_input->thread_info.state)) {
        aep_volume = u->aep_sink_input->thread_info.muted ?
            PA_VOLUME_MUTED : u->aep_sink_input->thread_info.soft_volume.values[0];
    }

    if (voice_voip_sink_active_iothread(u)) {
        if (u->voip_sink->thread_info.rewind_requested)
            pa_sink_process_rewind(u->voip_sink, 0);
        voice_aep_sink_process(u, &aepchunk);
        if (aep_volume != PA_VOLUME_MUTED && !pa_memblock_is_silence(aepchunk.memblock)) {
            if (aep_volume != PA_VOLUME_NORM) {
                pa_memchunk_make_writable(&aepchunk, 0);
                pa_optimized_apply_volume(&aepchunk, aep_volume);
            }
        }
        else if (!pa_memblock_is_silence(aepchunk.memblock)) {
            pa_memblock_unref(aepchunk.memblock);
            pa_silence_memchunk_get(&u->core->silence_cache,<commit_msg>voice: Print something to log when generating silence.<commit_after>/*
 * Copyright (C) 2010 Nokia Corporation.
 *
 * Contact: <NAME> <<EMAIL>>
 *          or <NAME> <<EMAIL>>
 *
 * These PulseAudio Modules are free software; you can redistribute
 * it and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation
 * version 2.1 of the License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 * USA.
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <assert.h>
#include <math.h>

#include <pulse/xmalloc.h>

#include <pulsecore/sink-input.h>
#include <pulsecore/source-output.h>
#include <pulsecore/module.h>
#include <pulsecore/modargs.h>
#include <pulsecore/namereg.h>
#include <pulsecore/log.h>
#include <pulsecore/mutex.h>
#include <pulsecore/atomic.h>
#include <pulsecore/semaphore.h>
#include <pulsecore/thread.h>
#include <pulsecore/sample-util.h>

#include "module-voice-userdata.h"
#include "voice-hw-sink-input.h"
#include "voice-util.h"
#include "voice-voip-sink.h"
#include "voice-raw-sink.h"
#include "voice-aep-ear-ref.h"
#include "voice-convert.h"
#include "pa-optimized.h"
#include "optimized.h"
#include "memory.h"
#include "voice-voip-source.h"

#include "module-voice-api.h"
#include "voice-hooks.h"

static unsigned int voice_dl_sideinfo_pop(struct userdata *u, int length) {
    unsigned int spc_flags = 0;

    pa_assert(u);
    pa_assert(length % u->aep_fragment_size == 0);

    while (length) {
        spc_flags = (unsigned int)pa_queue_pop(u->dl_sideinfo_queue);
        length -= u->aep_fragment_size;
    }

    return spc_flags & ~VOICE_SIDEINFO_FLAG_BOGUS;
}

/* Called from IO thread context. */
static void voice_aep_sink_process(struct userdata *u, pa_memchunk *chunk) {
    unsigned int spc_flags = 0;

    pa_assert(u);

    /*
     * note: HOOK_AEP_DOWNLINK must be called even if chunk is silent
     *       to ensure proper handling of SPEECH->DTX transitions
     */

    if (voice_voip_sink_active_iothread(u)) {
        aep_downlink params;

        pa_sink_render_full(u->voip_sink, u->aep_fragment_size, chunk);
        spc_flags = voice_dl_sideinfo_pop(u, u->aep_fragment_size);

        params.chunk = chunk;
        params.spc_flags = spc_flags;
        /* TODO: get rid of cmt boolean */
        params.cmt = TRUE;

        /* TODO: I think this should be called from behind the hook */
        pa_memchunk_make_writable(chunk, u->aep_fragment_size);

        meego_algorithm_hook_fire(u->hooks[HOOK_AEP_DOWNLINK], &params);
    }
    else {
        pa_silence_memchunk_get(&u->core->silence_cache,
                                u->core->mempool,
                                chunk,
                                &u->aep_sample_spec,
                                u->aep_fragment_size);
    }
}

/*** sink_input callbacks ***/
static int hw_sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
    struct userdata *u;
    meego_algorithm_hook_data hook_data;
    pa_memchunk aepchunk = { 0, 0, 0 };
    pa_memchunk rawchunk = { 0, 0, 0 };
    pa_volume_t aep_volume = PA_VOLUME_NORM;

    pa_assert(i);
    pa_sink_input_assert_ref(i);
    pa_assert_se(u = i->userdata);
    pa_assert(chunk);

#ifdef SINK_TIMING_DEBUG_ON
    static struct timeval tv_last = { 0, 0 };
    struct timeval tv_new;
    pa_rtclock_get(&tv_new);
    pa_usec_t ched_period = pa_timeval_diff(&tv_last, &tv_new);
    tv_last = tv_new;
#endif

    /* We only operate with N * u->hw_fragment_size chunks. */
    if (length > u->hw_fragment_size_max)
        length = u->hw_fragment_size_max;
    else if (0 != (length % u->hw_fragment_size)) {
        if (voice_voip_sink_active_iothread(u)) {
            pa_log_debug("%s asked for %zu bytes, which isn't divisible with the current fragment size (%zu). Returning silence and resetting the ear ref loop.",
                         i->sink->name, length, u->hw_fragment_size);
            pa_silence_memchunk_get(&u->core->silence_cache,
                    u->core->mempool,
                    chunk,
                    &u->hw_sample_spec,
                    length);
            voice_aep_ear_ref_loop_reset(u);
            return;
        }
        else
            length += u->hw_fragment_size - (length % u->hw_fragment_size);
    }

    if (u->aep_sink_input && PA_SINK_INPUT_IS_LINKED(
            u->aep_sink_input->thread_info.state)) {
        aep_volume = u->aep_sink_input->thread_info.muted ?
            PA_VOLUME_MUTED : u->aep_sink_input->thread_info.soft_volume.values[0];
    }

    if (voice_voip_sink_active_iothread(u)) {
        if (u->voip_sink->thread_info.rewind_requested)
            pa_sink_process_rewind(u->voip_sink, 0);
        voice_aep_sink_process(u, &aepchunk);
        if (aep_volume != PA_VOLUME_MUTED && !pa_memblock_is_silence(aepchunk.memblock)) {
            if (aep_volume != PA_VOLUME_NORM) {
                pa_memchunk_make_writable(&aepchunk, 0);
                pa_optimized_apply_volume(&aepchunk, aep_volume);
            }
        }
        else if (!pa_memblock_is_silence(aepchunk.memblock)) {
            pa_memblock_unref(aepchunk.memblock);
            pa_silence_memchunk_get(&u->core->silence_cache,
{'fraction_non_alphanumeric': 0.10952853150635536, 'fraction_numerical': 0.005769404128729829, 'mean_word_length': 2.8440748440748442, 'pattern_counts': {'":': 0, '<': 47, '<?xml version=': 0, '>': 130, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2740103', 'n_tokens_mistral': 3924, 'n_tokens_neox': 3830, 'n_words': 831}