| Updated: October 28, 2024 |
This is a sample application shows how to get the current active audio types.
/*
* $QNXLicenseC:
* Copyright 2017, QNX Software Systems.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You
* may not reproduce, modify or distribute this software except in
* compliance with the License. You may obtain a copy of the License
* at: http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OF ANY KIND, either express or implied.
*
* This file may contain contributions from others, either as
* contributors under the License or as licensors under other terms.
* Please review this entire file for other proprietary rights or license
* notices, as well as the QNX Development Suite License Guide at
* http://licensing.qnx.com/license-guide/ for other information.
* $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <devctl.h>
#include <errno.h>
#include <sys/asoundlib.h>
//*****************************************************************************
/* *INDENT-OFF* */
#ifdef __USAGE
%C [Options]
Options:
-a<cardno> Card number
-n<output_id> Ducking output ID to monitor
-l Use legacy status events
#endif
/* *INDENT-ON* */
//*****************************************************************************
static void audiomgmt_cb ( snd_ctl_t *hdl, void *private_data, int cmd)
{
int status, i, j;
const char *ducking_output = private_data;
switch (cmd)
{
case SND_CTL_READ_AUDIOMGMT_CHG: /* deprecated - Use SND_CTL_READ_AUDIOMGMT_STATUS_CHG */
{
snd_ducking_status_t *info = NULL;
snd_ducking_type_status_t *active_type = NULL;
if ((status = snd_ctl_ducking_read(hdl, ducking_output, &info )) != EOK)
{
printf("Failed to read ducking info - %s\n", snd_strerror(status));
return;
}
printf("\nActive audio types = %d\n", info->ntypes);
/* The active_types structure is variable in size based on the number of pids it references, so we must
* walk the active_type member of the info structure using the SND_DUCKING_STATUS_NEXT_TYPE() marco
*/
for (i = 0, active_type = info->active_types; i < info->ntypes; i++,
active_type = SND_DUCKING_STATUS_NEXT_TYPE(active_type))
{
printf("Audio Type %s, Priority %d\n", active_type->name, active_type->prio);
printf("\tPids (%d): ", active_type->npids);
for (j = 0; j < active_type->npids; j++)
{
printf("%d ", active_type->pids[j]);
}
printf("\n");
}
/* snd_ctl_ducking_read() will allocate the info buffer, so we must free it */
free(info);
break;
}
case SND_CTL_READ_AUDIOMGMT_STATUS_CHG:
{
snd_ducking_priority_status_t *info = NULL;
if ((status = snd_ctl_ducking_status_read(hdl, ducking_output, &info )) != EOK)
{
printf("Failed to read ducking info - %s\n", snd_strerror(status));
return;
}
printf("Active Subchns (%d):\n", info->nsubchns);
/* The priority status structure is variable in size based on the number of subchns it references, so we must
* walk the entries member of the info structure using the SND_DUCKING_STATUS_NEXT_ENTRY() marco
*/
for (i = 0; i < info->nsubchns; i++)
{
printf("\tPriority: %d\n", info->subchns[i].prio);
printf("\tPid: %d\n", info->subchns[i].pid);
printf("\tAudio Type: %s\n", info->subchns[i].name);
printf("\tState: ");
if (info->subchns[i].state & SND_PCM_DUCKING_STATE_FORCED_ACTIVE)
printf("FORCED_ACTIVE ");
else
printf("ACTIVE ");
if (info->subchns[i].state & SND_PCM_DUCKING_STATE_DUCKED)
printf("| DUCKED ");
if (info->subchns[i].state & SND_PCM_DUCKING_STATE_HARD_SUSPENDED)
printf("| HARD_SUSPENDED ");
if (info->subchns[i].state & SND_PCM_DUCKING_STATE_SOFT_SUSPENDED)
printf("| SOFT_SUSPENDED ");
if (info->subchns[i].state & SND_PCM_DUCKING_STATE_PAUSED)
printf("| PAUSED ");
if (info->subchns[i].state & (SND_PCM_DUCKING_STATE_MUTE_BY_HIGHER|SND_PCM_DUCKING_STATE_MUTE_BY_SAME))
printf("| MUTED ");
if (info->subchns[i].ducked_by & (SND_PCM_DUCKED_BY_SAME_PRIO|SND_PCM_DUCKED_BY_HIGHER_PRIO))
{
printf("\n\tDucked by: ");
if (info->subchns[i].ducked_by & SND_PCM_DUCKED_BY_SAME_PRIO)
printf("SAME PRIORITY ");
else if (info->subchns[i].ducked_by & SND_PCM_DUCKED_BY_HIGHER_PRIO)
printf("HIGHER PRIORITY ");
if (info->subchns[i].ducked_by & SND_PCM_DUCKED_BY_NONTRANSIENT)
printf("| NON-TRANSIENT");
else
printf("| TRANSIENT");
}
printf("\n\n");
}
printf("\n");
/* snd_ctl_ducking_status_read() will allocate the info buffer, so we must free it */
free(info);
break;
}
default:
break;
}
}
int main (int argc, char *argv[])
{
int c;
int legacy = 0;
fd_set rfds;
int card = 0, ctl_fd;
snd_ctl_t *handle;
snd_ctl_callbacks_t callbacks;
snd_ctl_filter_t filter;
char *ducking_output = NULL;
optind = 1;
while ((c = getopt(argc, argv, "a:n:l")) != EOF)
{
switch (c)
{
case 'a':
card = strtol (optarg, &optarg, 0);
break;
case 'n':
ducking_output = optarg;
break;
case 'l':
legacy = 1;
break;
default:
break;
}
}
if (ducking_output == NULL)
{
printf("Ducking output not provided\n");
return 1;
}
if (snd_ctl_open(&handle, card) != EOK)
{
printf("Failed to open control device on card %d\n", card);
return 1;
}
ctl_fd = snd_ctl_file_descriptor(handle);
memset(&callbacks, 0, sizeof (callbacks));
callbacks.private_data = ducking_output;
callbacks.audiomgmt = &audiomgmt_cb;
/* Enable audio management status events */
if (legacy)
filter.enable = SND_CTL_EVENT_MASK(SND_CTL_READ_AUDIOMGMT_CHG);
else
filter.enable = SND_CTL_EVENT_MASK(SND_CTL_READ_AUDIOMGMT_STATUS_CHG);
snd_ctl_set_filter(handle, &filter);
FD_ZERO(&rfds);
while (1)
{
FD_SET(ctl_fd, &rfds);
if (select(ctl_fd + 1, &rfds, NULL, NULL, NULL) == -1)
{
printf("Select failed - %s\n", strerror(errno));
return 1;
}
if (FD_ISSET(ctl_fd, &rfds))
{
snd_ctl_read(handle, &callbacks);
}
}
snd_ctl_close (handle);
return 0;
}
#if defined(__QNXNTO__) && defined(__USESRCVERSION)
#include <sys/srcversion.h>
__SRCVERSION("$URL$ $Rev$")
#endif