Exploration du moteur VoIP Mediastreamer2. Partie 5

Le matériel de l'article est tiré de mon canal zen.

Détecteur de tonalité

À la fin article Nous avons créé un indicateur de niveau de signal. Dans celui-ci, nous apprendrons comment détecter un signal sonore.

Exploration du moteur VoIP Mediastreamer2. Partie 5

Autrefois, lorsque toutes les familles n'avaient pas de téléviseur et que la moitié d'entre elles changeaient de chaîne à l'aide de pinces, des nouvelles intrigantes sont apparues dans des revues de la presse technique étrangère selon lesquelles un fabricant de téléviseurs équipait ses appareils d'une télécommande sans fil. D'après les détails, on savait que la télécommande fonctionnait sans piles grâce à l'utilisation d'une approche inhabituelle - la télécommande était mécanique et était un hybride d'un instrument de musique - un métallophone et un revolver. Le tambour du revolver contenait des cylindres métalliques de différentes longueurs, et lorsque le percuteur frappait l'un d'eux, le cylindre commençait à sonner à sa propre fréquence. Vraisemblablement à l'échographie. L'électronique du téléviseur a entendu ce signal et, après avoir déterminé sa fréquence, a effectué l'action appropriée : changer de chaîne, modifier le volume, éteindre le téléviseur.

Aujourd'hui, nous allons tenter de reconstruire ce système de transmission de commandes, en utilisant nos connaissances du streamer multimédia.

Pour simuler une télécommande, nous utiliserons le texte de notre exemple de générateur de tonalité. Nous y ajouterons le contrôle de la fréquence du générateur à partir des frappes au clavier et un récepteur avec un décodeur qui transmettra les commandes reçues à la console. Après le changement, le générateur doit produire des tonalités de 6 fréquences, avec lesquelles nous encoderons les commandes pour augmenter/diminuer le volume, changer de chaîne, allumer/éteindre le téléviseur. Pour configurer le détecteur, la structure suivante est utilisée :

struct _MSToneDetectorDef{  
     char tone_name[8];     
     int frequency; /**<Expected frequency of the tone*/ 
     int min_duration; /**<Min duration of the tone in milliseconds */ 
     float min_amplitude; /**<Minimum amplitude of the tone, 1.0 corresponding to the normalized 0dbm level */
};

typedef struct _MSToneDetectorDef MSToneDetectorDef;

Un détecteur peut recevoir 10 de ces structures, de sorte qu'un détecteur peut être configuré pour détecter dix signaux à deux tons. Mais nous n'utiliserons que six signaux à tonalité unique. Pour transférer les paramètres vers le détecteur, la méthode MS_TONE_DETECTOR_ADD_SCAN est utilisée.

Pour que le détecteur nous avertisse qu'un signal avec les composantes de fréquence souhaitées est arrivé à son entrée, nous devons lui fournir une fonction de rappel qu'il lancera dans ce cas. Cela se fait à l'aide de la fonction ms_filter_set_notify_callback(). En arguments, il reçoit un pointeur vers le filtre, un pointeur vers la fonction de rappel et un pointeur vers les données que nous souhaitons transmettre à la fonction de rappel (données utilisateur).

Lorsque le détecteur est déclenché, la fonction de rappel recevra des données utilisateur, un pointeur vers le filtre du détecteur, un identifiant d'événement et une structure décrivant l'événement :


/** * Structure carried as argument of the MS_TONE_DETECTOR_EVENT**/
struct _MSToneDetectorEvent{ 
      char tone_name[8];       /* Имя тона которое мы ему назначили при настройке детектора. */
      uint64_t tone_start_time;   /* Время в миллисекундах, когда тон был обнаружен. */
};

typedef struct _MSToneDetectorEvent MSToneDetectorEvent;

Le schéma fonctionnel du traitement du signal est présenté dans l’image du titre.

Eh bien, maintenant le programme lui-même se code avec des commentaires.

/* Файл mstest4.c Имитатор пульта управления и приемника. */
#include <mediastreamer2/msfilter.h>
#include <mediastreamer2/msticker.h>
#include <mediastreamer2/dtmfgen.h>
#include <mediastreamer2/mssndcard.h>
#include <mediastreamer2/msvolume.h>
#include <mediastreamer2/mstonedetector.h>

/* Подключаем заголовочный файл с функциями управления событиями
 * медиастримера. */
#include <mediastreamer2/mseventqueue.h>

/* Функция обратного вызова, она будет вызвана фильтром, как только он
 * обнаружит совпадение характеристик входного сигнала с заданными. */
static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id,
        MSToneDetectorEvent *ev)
{
    printf("                      Принята команда: %sn", ev->tone_name);
}

int main()
{
    ms_init();

    /* Создаем экземпляры фильтров. */
    MSFilter  *voidsource = ms_filter_new(MS_VOID_SOURCE_ID);
    MSFilter  *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);
    MSFilter  *volume = ms_filter_new(MS_VOLUME_ID);
    MSSndCard *card_playback =
        ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());
    MSFilter  *snd_card_write = ms_snd_card_create_writer(card_playback);
    MSFilter  *detector = ms_filter_new(MS_TONE_DETECTOR_ID);

    /* Очищаем массив находящийся внутри детектора тонов, он описывает
     * особые приметы разыскиваемых сигналов.*/
    ms_filter_call_method(detector, MS_TONE_DETECTOR_CLEAR_SCANS, 0);

    /* Создаем источник тактов - тикер. */
    MSTicker *ticker=ms_ticker_new();

    /* Соединяем фильтры в цепочку. */
    ms_filter_link(voidsource, 0, dtmfgen, 0);
    ms_filter_link(dtmfgen, 0, volume, 0);
    ms_filter_link(volume, 0, detector, 0);
    ms_filter_link(detector, 0, snd_card_write, 0);

    /* Подключаем к фильтру функцию обратного вызова. */
    ms_filter_set_notify_callback(detector,
            (MSFilterNotifyFunc)tone_detected_cb, NULL);

    /* Подключаем источник тактов. */
    ms_ticker_attach(ticker,voidsource);

    /* Создаем массив, каждый элемент которого описывает характеристику
     * одного из тонов, который требуется обнаруживать: Текстовое имя
     * данного элемента, частота в герцах, длительность в миллисекундах,
     * минимальный уровень относительно 0,775В. */  
    MSToneDetectorDef  scan[6]=
    {
        {"V+",  440, 100, 0.1}, /* Команда "Увеличить громкость". */
        {"V-",  540, 100, 0.1}, /* Команда "Уменьшить громкость". */
        {"C+",  640, 100, 0.1}, /* Команда "Увеличить номер канала". */
        {"C-",  740, 100, 0.1}, /* Команда "Уменьшить номер канала". */
        {"ON",  840, 100, 0.1}, /* Команда "Включить телевизор". */
        {"OFF", 940, 100, 0.1}  /* Команда "Выключить телевизор". */
    };

    /* Передаем в детектор тонов приметы сигналов. */
    int i;
    for (i = 0; i < 6; i++)
    {
        ms_filter_call_method(detector, MS_TONE_DETECTOR_ADD_SCAN,
                &scan[i]);
    }

    /* Настраиваем структуру, управляющую выходным сигналом генератора.*/
    MSDtmfGenCustomTone dtmf_cfg;
    dtmf_cfg.tone_name[0] = 0;
    dtmf_cfg.duration = 1000;
    dtmf_cfg.frequencies[0] = 440;
    /* Будем генерировать один тон, частоту второго тона установим в 0.*/
    dtmf_cfg.frequencies[1] = 0;
    dtmf_cfg.amplitude = 1.0;
    dtmf_cfg.interval = 0.;
    dtmf_cfg.repeat_count = 0.;

    /* Организуем цикл сканирования нажатых клавиш. Ввод нуля завершает
     * цикл и работу программы. */
    char key='9';
    printf("Нажмите клавишу команды, затем ввод.n"
        "Для завершения программы введите 0.n");
    while(key != '0')
    {
        key = getchar();
        if ((key >= 49) && (key <= 54))
        {
                printf("Отправлена команда: %cn", key);
            /* Устанавливаем частоту генератора в соответствии с
             * кодом нажатой клавиши.*/
            dtmf_cfg.frequencies[0] = 440 + 100*(key-49);

            /* Включаем звуковой генератор c обновленной частотой. */
            ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,
                    (void*)&dtmf_cfg);
        }
        ms_usleep(20000);
    }
}

Nous compilons et exécutons le programme. Si tout fonctionne correctement, après le lancement, nous devrions obtenir quelque chose comme ce comportement du programme :

$ ./mstest4
ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0
ALSA lib control.c:954:(snd_ctl_open_noupdate) Invalid CTL default:0
ortp-warning-Could not attach mixer to card: Invalid argument
ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default:0
ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0
ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default:0
ortp-warning-Strange, sound card Intel 82801AA-ICH does not seems to be capable of anything, retrying with plughw...
Нажмите клавишу команды, затем ввод.
Для завершения программы введите 0.
ortp-warning-alsa_set_params: periodsize:256 Using 256
ortp-warning-alsa_set_params: period:8 Using 8

Appuyez sur n'importe quelle touche de « 1 » à « 6 », en confirmant avec la touche « Entrée », vous devriez obtenir quelque chose comme cette liste :


2
Отправлена команда: 2
                      Принята команда: V-
1
Отправлена команда: 1
                      Принята команда: V+
3
Отправлена команда: 3
                      Принята команда: C+
4
Отправлена команда: 4
                      Принята команда: C-
0
$

Nous constatons que les tonalités de commande sont envoyées avec succès et que le détecteur les détecte.

Dans le prochain article, nous aborderons la transmission d'un signal audio sur un réseau Ethernet à l'aide du protocole RTP et l'appliquerons immédiatement à notre télécommande.

Source: habr.com

Ajouter un commentaire