ALSA volume change callback not triggering? - callback

I have a function that I'm setting as the callback, but events are happening and the funciton is not being called. Is there something else I need to do?
// static
int volume_change_callback(snd_mixer_elem_t* elem,
unsigned int mask) {
// Do stuff
}
snd_mixer_elem_set_callback(element, volume_change_callback);

You need to use snd_mixer_handle_events() to actually have the callback get called. (http://www.alsa-project.org/alsa-doc/alsa-lib/group___mixer.html#gae0cfb6b50ec2493281107b0649f87cb8)
Check out amixer.c (https://fossies.org/dox/alsa-utils-1.0.29/amixer_8c_source.html) for an example of handling events:
while (1) {
int res;
res = snd_mixer_wait(handle, -1);
if (res >= 0) {
printf("Poll ok: %i\n", res);
res = snd_mixer_handle_events(handle);
assert(res >= 0);
}
}

Related

65535 cnt value on TTN network

I'm trying to run Lmic library build for arduino (https://github.com/matthijskooijman/arduino-lmic) to work with my Renesas Synergy SK-S7G2 board using e2 studio.
I have altered the hal.cpp file and now the code runs perfectly and I can see the up-link message on the TTN network, The problem that I am facing is that my frame is somehow changing between aes encryption (my guess) because I have checked it before encryption and it shows the LMIC.frame[6] and
LMIC.frame[7] values to be 0x00 but for some reason what I am receiving on the TTN network is 0xFF. and because of this the cnt on TTN shows 65535 as the first count.
The library has 2 aes methods which can be used and I have tried both but they give me the same result.
The reasons I have come up with so far is:
32 bit arm m4 processor may be the cause, as the library was intended for 8 bit arduino (but library also has a 32bit processor version for aes and I have tried that as well but got same result)
My hal_ticks() function is still not doing what it is supposed to do.
I would love an input from anyone, below you can see the console output on e2 studio and the physical payload received on the TTN network. I am also attaching the hal.c file that I have made.
Thank you in advance
physical payload received on TTN
406511012680 FFFF 0171F9EF1810C3B61F4D4EDE940844A945CE
console messages while running on e2 studio
Starting..
Time: 0
RXMODE_RSSI
5824: engineUpdate, opmode=0x808
7349: TXMODE, freq=868100000, len=26, SF=7, BW=125, CR=4/5, IH=0
Packet queued
42111: RXMODE_SINGLE, freq=868100000, SF=7, BW=125, CR=4/5, IH=0
73505: RXMODE_SINGLE, freq=869525000, SF=9, BW=125, CR=4/5, IH=0
75435Event
EV_TXCOMPLETE (includes waiting for RX windows)
79028: engineUpdate, opmode=0x900
hal.c file
/*
* hal.c
*
* Created on: Jul 4, 2019
* Author: areeb
*/
/*******************************************************************************
* Copyright (c) 2015 Matthijs Kooijman
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* This the HAL to run LMIC on top of the Arduino environment.
*******************************************************************************/
#include <hal/hal.h>
#include "hal_data.h"
#include <stdio.h>
#include "../lmic/lmic.h"
ssp_err_t err;
u4_t t ;
unsigned int ticks=0, fg=0;
u2_t cnt=0 ;
uint32_t scaled = 0, ch=0;
static volatile bool spi_done = false;
static bool dio_states[3] = {0};
void spi_callback(spi_callback_args_t *p_args)
{
SSP_PARAMETER_NOT_USED(p_args);
spi_done= true;
}
void timer0_callback(timer_callback_args_t *p_args)
{
SSP_PARAMETER_NOT_USED(p_args);
ticks++;
}
void irq_callback(external_irq_callback_args_t *p_args)
{
if(p_args->channel == 1)
{
dio_states[0]=1;
radio_irq_handler(0);
dio_states[0]=0;
}
else if(p_args->channel == 2)
{
dio_states[1]=1;
radio_irq_handler(1);
dio_states[0]=0;
}
else if(p_args->channel == 14)
{
dio_states[2]=1;
radio_irq_handler(2);
}
else
{
;
}
// if(p_args->channel == 14)
// {
// radio_irq_handler(2);
// }
}
// -----------------------------------------------------------------------------
// I/O
//#define nss (IOPORT_PORT_04_PIN_13)
//
//#define rst (IOPORT_PORT_05_PIN_11)
u1_t transmit[1]={0},ccc=0;
u1_t recv[1]={0};
static void hal_io_init () {
// g_ioport.p_api->pinDirectionSet(lmic_pins.nss, IOPORT_DIRECTION_OUTPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[0], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[0], IOPORT_DIRECTION_INPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[1], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[1], IOPORT_DIRECTION_INPUT);
// g_ioport.p_api->pinCfg(lmic_pins.dio[2], IOPORT_DIRECTION_INPUT|IOPORT_CFG_EVENT_FALLING_EDGE);
// g_ioport.p_api->pinDirectionSet(lmic_pins.dio[2], IOPORT_DIRECTION_INPUT);
}
// val == 1 => tx 1
void hal_pin_rxtx (u1_t val) {
}
// set radio RST pin to given value (or keep floating!)
void hal_pin_rst (u1_t val) {
g_ioport.p_api->init(g_ioport.p_cfg);
if(val == 0 || val == 1)
{
g_ioport.p_api->pinCfg(lmic_pins.rst, IOPORT_DIRECTION_OUTPUT);
g_ioport.p_api->pinDirectionSet(lmic_pins.rst, IOPORT_DIRECTION_OUTPUT);
if(val == 0)
g_ioport.p_api->pinWrite(lmic_pins.rst,IOPORT_LEVEL_LOW);
else if (val == 1)
g_ioport.p_api->pinWrite(lmic_pins.rst,IOPORT_LEVEL_HIGH);
}
else
{
g_ioport.p_api->pinCfg(lmic_pins.rst, IOPORT_DIRECTION_INPUT);
g_ioport.p_api->pinDirectionSet(lmic_pins.rst, IOPORT_DIRECTION_INPUT);
}
}
ioport_level_t readpin;
u1_t rd=0;
//static void hal_io_check() {
//
// uint8_t i;
// for (i = 0; i < NUM_DIO; ++i) {
// if (lmic_pins.dio[i] == 0xff)
// continue;
// g_ioport.p_api->pinRead(lmic_pins.dio[i], &readpin);
// if(readpin == IOPORT_LEVEL_HIGH)
// rd = 1;
// else
// rd = 0;
//
// if (dio_states[i] != readpin) {
// dio_states[i] = !dio_states[i];
// if (dio_states[i])
// radio_irq_handler(i);
// }
// }
//
//
//}
void hal_io_check() {
uint8_t i;
// for (i = 0; i < 3; ++i) {
// if (lmic_pins.dio[i] == 0xff)
// continue;
//
// if (dio_states[i] != 0) {
// dio_states[i] = !dio_states[i];
// if (dio_states[i])
// radio_irq_handler(i);
// }
// }
// radio_irq_handler(0);
}
// -----------------------------------------------------------------------------
// SPI
//static const SPISettings settings(10E6, MSBFIRST, SPI_MODE0);
static void hal_spi_init () {
err = g_spi0.p_api->open(g_spi0.p_ctrl,g_spi0.p_cfg);
err = g_timer0.p_api->open(g_timer0.p_ctrl,g_timer0.p_cfg);
err = g_timer0.p_api->start(g_timer0.p_ctrl);
g_external_irq0.p_api->open(g_external_irq0.p_ctrl,g_external_irq0.p_cfg);
g_external_irq0.p_api->enable(g_external_irq0.p_ctrl);
g_external_irq0.p_api->triggerSet(g_external_irq0.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
g_external_irq1.p_api->open(g_external_irq1.p_ctrl,g_external_irq1.p_cfg);
g_external_irq1.p_api->enable(g_external_irq1.p_ctrl);
g_external_irq1.p_api->triggerSet(g_external_irq1.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
g_external_irq2.p_api->open(g_external_irq2.p_ctrl,g_external_irq2.p_cfg);
g_external_irq2.p_api->enable(g_external_irq2.p_ctrl);
g_external_irq2.p_api->triggerSet(g_external_irq2.p_ctrl, EXTERNAL_IRQ_TRIG_BOTH_EDGE);
}
void hal_pin_nss (u1_t val) {
g_ioport.p_api->pinDirectionSet(lmic_pins.nss, IOPORT_DIRECTION_OUTPUT);
if(val == 0)
g_ioport.p_api->pinWrite(lmic_pins.nss,IOPORT_LEVEL_LOW);
else if(val == 1)
g_ioport.p_api->pinWrite(lmic_pins.nss,IOPORT_LEVEL_HIGH);
}
// perform SPI transaction with radio
u1_t hal_spi (u1_t out) {
if((out & 0x80) == 0x80)
{
uint8_t temp[1] = {out};
g_spi0.p_api->write(g_spi0.p_ctrl, (const void*)temp,1,SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
return 0;
}
else if((out > 0x00) && (out & 0x80) != 0x80)
{
ccc = out;
uint8_t temp[1] = {out};
g_spi0.p_api->write(g_spi0.p_ctrl, (const void*)temp,1,SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
}
else if(out == 0x00)
{
g_spi0.p_api->read(g_spi0.p_ctrl, recv, sizeof(recv), SPI_BIT_WIDTH_8_BITS);
while(false == spi_done)
{
;
}
spi_done = false;
return recv[0];
}
return recv[0];
}
// -----------------------------------------------------------------------------
// TIME
static void hal_time_init () {
// Nothing to do
}
u4_t hal_ticks () {
// Because micros() is scaled down in this function, micros() will
// overflow before the tick timer should, causing the tick timer to
// miss a significant part of its values if not corrected. To fix
// this, the "overflow" serves as an overflow area for the micros()
// counter. It consists of three parts:
// - The US_PER_OSTICK upper bits are effectively an extension for
// the micros() counter and are added to the result of this
// function.
// - The next bit overlaps with the most significant bit of
// micros(). This is used to detect micros() overflows.
// - The remaining bits are always zero.
//
// By comparing the overlapping bit with the corresponding bit in
// the micros() return value, overflows can be detected and the
// upper bits are incremented. This is done using some clever
// bitwise operations, to remove the need for comparisons and a
// jumps, which should result in efficient code. By avoiding shifts
// other than by multiples of 8 as much as possible, this is also
// efficient on AVR (which only has 1-bit shifts).
// g_timer0.p_api->stop(g_timer0.p_ctrl);
// static uint8_t overflow = 0;
// Scaled down timestamp. The top US_PER_OSTICK_EXPONENT bits are 0,
// the others will be the lower bits of our return value.
// u4_t t = ticks;
// g_timer0.p_api->counterGet(g_timer0.p_ctrl, &cnt);
// cnt = 65535-cnt;
// if( (cnt > 65000) && (cnt < 65535 ) )
// {
// g_timer0.p_api->reset(g_timer0.p_ctrl);
// cnt=0;
// t++;
// }
// scaled = ticks >> US_PER_OSTICK_EXPONENT; // 625
// Most significant byte of scaled
// uint8_t msb = scaled >> 24;
// Mask pointing to the overlapping bit in msb and overflow.
// const uint8_t mask = (1 << (7 - US_PER_OSTICK_EXPONENT));
// Update overflow. If the overlapping bit is different
// between overflow and msb, it is added to the stored value,
// so the overlapping bit becomes equal again and, if it changed
// from 1 to 0, the upper bits are incremented.
// overflow += (msb ^ overflow) & mask;
// Return the scaled value with the upper bits of stored added. The
// overlapping bit will be equal and the lower bits will be 0, so
// bitwise or is a no-op for them.
// g_timer0.p_api->start(g_timer0.p_ctrl);
// return scaled | ((uint32_t)overflow << 24);
// 0 leads to correct, but overly complex code (it could just return
// micros() unmodified), 8 leaves no room for the overlapping bit.
// static_assert(US_PER_OSTICK_EXPONENT > 0 && US_PER_OSTICK_EXPONENT < 8, "Invalid US_PER_OSTICK_EXPONENT value");
t = ticks;
//
//// hal_disableIRQs();
///
g_timer0.p_api->counterGet(g_timer0.p_ctrl, &cnt);
if(cnt != 0 )
cnt = 65535 - cnt;
// if( (cnt < 500) )
// {
// g_timer0.p_api->reset(g_timer0.p_ctrl);
// cnt=0;
// t++;
// }
// hal_enableIRQs();
return ((t<<16)|cnt);
}
// Returns the number of ticks until time. Negative values indicate that
// time has already passed.
static s4_t delta_time(u4_t time) {
u4_t t = hal_ticks();
s4_t d = time - t;
if( d<=0 ) return 0; // in the past
if( (d>>16)!=0 ) return 0xFFFF; // far ahead
return (u2_t)d;
}
void hal_waitUntil (u4_t time) {
while( delta_time(time) != 0 );
}
// s4_t delta = delta_time(time);
// // From delayMicroseconds docs: Currently, the largest value that
// // will produce an accurate delay is 16383.
// while (delta > (16000 / US_PER_OSTICK)) {
// R_BSP_SoftwareDelay(16, BSP_DELAY_UNITS_MILLISECONDS);
// delta -= (16000 / US_PER_OSTICK);
// }
// if (delta > 0)
// R_BSP_SoftwareDelay((delta * US_PER_OSTICK), BSP_DELAY_UNITS_MICROSECONDS);
//// delayMicroseconds(delta * US_PER_OSTICK);
//}
// check and rewind for target time
u1_t hal_checkTimer (u4_t time) {
// No need to schedule wakeup, since we're not sleeping
return delta_time(time) <= 0;
}
static uint8_t irqlevel = 0;
void hal_disableIRQs () {
// __disable_irq();
// g_timer0.p_api->close(g_timer0.p_ctrl);
// g_external_irq1.p_api->disable(g_external_irq1.p_ctrl);
// g_external_irq2.p_api->disable(g_external_irq2.p_ctrl);
irqlevel++;
}
void hal_enableIRQs () {
if(--irqlevel == 0) {
// __enable_irq();
// g_timer0.p_api->open(g_timer0.p_ctrl,g_timer0.p_cfg);
// g_external_irq1.p_api->enable(g_external_irq1.p_ctrl);
// g_external_irq2.p_api->enable(g_external_irq2.p_ctrl);
// Instead of using proper interrupts (which are a bit tricky
// and/or not available on all pins on AVR), just poll the pin
// values. Since os_runloop disables and re-enables interrupts,
// putting this here makes sure we check at least once every
// loop.
//
// As an additional bonus, this prevents the can of worms that
// we would otherwise get for running SPI transfers inside ISRs
hal_io_check();
}
hal_io_check();
}
void hal_sleep () {
// Not implemented
}
// -----------------------------------------------------------------------------
#if defined(LMIC_PRINTF_TO)
static int uart_putchar (char c, FILE *)
{
LMIC_PRINTF_TO.write(c) ;
return 0 ;
}
void hal_printf_init() {
// create a FILE structure to reference our UART output function
static FILE uartout;
memset(&uartout, 0, sizeof(uartout));
// fill in the UART file descriptor with pointer to writer.
fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
// The uart is the standard output device STDOUT.
stdout = &uartout ;
}
#endif // defined(LMIC_PRINTF_TO)
void hal_init () {
// configure radio I/O and interrupt handler
hal_io_init();
// configure radio SPI
hal_spi_init();
// configure timer and interrupt handler
hal_time_init();
#if defined(LMIC_PRINTF_TO)
// printf support
hal_printf_init();
#endif
}
void hal_failed (const char *file, u2_t line) {
}

Unpacking iterable in Python extension

I'm trying to translate a, b, c, d = iterable to Python's C/API.
I'm looking for a function similar to PyArg_ParseTuple, just for iterables.
In other words, something in the area of PyIter_Parse or PyObject_ParseIterable, if such functions would have existed.
Any tips how to implement it?
No, there is no helper function that can do this for you.
You'd have to use PyIter_Next() up to max times to retrieve values, raise an exception when you can't get at least min values, and then just build a tuple from that.
Something like (untested, largely pilfered from PySequence_Tuple()):
int
PyIter_LimitedTuple(PyObject *v, Py_ssize_t min, Py_ssize_t max)
{
PyObject *it; /* iter(v) */
PyObject *result = NULL;
Py_ssize_t j;
it = PyObject_GetIter(v);
if (it == NULL)
return NULL;
/* allocate space. */
result = PyTuple_New(max);
if (result == NULL)
goto Fail;
/* Fill the tuple. */
for (j = 0; ; ++j) {
PyObject *item = PyIter_Next(it);
if (item == NULL) {
if (PyErr_Occurred())
goto Fail;
break;
}
if (j > max) {
PyErr_Format(PyExc_ValueError,
"too many values to unpack");
goto Fail;
}
PyTuple_SET_ITEM(result, j, item);
}
if (j < min) {
PyErr_Format(PyExc_ValueError,
"need more than %d value to unpack",
j);
goto Fail;
}
/* Cut tuple back if fewer than max items were available. */
if (j < max &&
_PyTuple_Resize(&result, j) != 0)
goto Fail;
Py_DECREF(it);
return result;
Fail:
Py_XDECREF(result);
Py_DECREF(it);
return NULL;
}
then pass the resulting tuple to PyArg_UnpackTuple().

Sockets using GetQueuedCompletionStatus and ERROR_MORE_DATA

I am trying to use GetQueuedCompletionStatus with winsocks, but I can't seem to get it right. The procedure is as follows:
void foo() {
...
SOCKET sck = WSASocket(AF_INET, SOCK_DGRAM, 0,
NULL, 0, WSA_FLAG_OVERLAPPED);
....
bind(sck,(struct sockaddr *)&addr,sizeof(struct sockaddr_in));
HANDLE hPort = CreateIoCompletionPort((HANDLE)sck, NULL, 0, 0 );
OVERLAPPED pOverlapped = {0,};
WSARecvFrom(sck,NULL,0,NULL,NULL,(struct sockaddr *)&laddr,&lsize,&pOverlapped,0);
BOOL bReturn = GetQueuedCompletionStatus(
hPort,
&rbytes,
(LPDWORD)&lpContext,
&pOutOverlapped,
INFINITE);
...
}
I then send some network data to the bound port from an external tool. GetQueuedCompletionStatus returns FALSE, and GetLastError() returns ERROR_MORE_DATA, which sounds correct, since I hadn't provided a buffer in WSARecvFrom.
The question is how can I provide a buffer to actually get the data from the failed I/O operation?
I tried to issue a WSARecvFrom with the original overlapped structured, but it simply queues another read, and a subsequent call to GetQueuedCompletionStatus does not return until more network data is sent.
Calling WSARecvFrom without an overlapped structure blocks it, and it also doesn't return until more network data is sent.
So, how can I handle ERROR_MORE_DATA properly, without losing the data from the first operation?
You must provide a buffer to WSARecvFrom(), just like with any read operation regardless of whether you use IOCP or not. You must ensure the buffer stays valid in memory until the IOCP operation is complete. IOCP fills the buffer you provide and then notifies the completion port when finished.
UDP cannot transfer more than 65535 bytes in a single datagram, so you can use that as your max buffer size.
In your example, your code is written to run synchronously (defeating the purpose of using IOCP at all), so you can use a local buffer:
void foo() {
...
SOCKET sck = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (sck == INVALID_SOCKET)
{
// error, do something...
return;
}
....
bind(sck,(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
HANDLE hPort = CreateIoCompletionPort((HANDLE)sck, NULL, 0, 0 );
if (!hPort)
{
// error, do something...
return;
}
WSAOVERLAPPED Overlapped = {0};
Overlapped.hEvent = WSACreateEvent();
BYTE buffer[0xFFFF];
DWORD dwBytesRecvd = 0;
DWORD dwFlags = 0;
sockaddr_in fromaddr = {0};
int fromaddrlen = sizeof(fromaddr);
WSABUF buf;
buf.len = sizeof(buffer);
buf.buf = buffer;
int iRet = WSARecvFrom(sck, &buf, 1, &dwBytesRecvd, &dwFlags, (sockaddr*)&fromaddr, &fromaddrlen, &Overlapped, NULL);
if (iRet == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
// error, do something...
return;
}
DWORD rBytes;
ULONG_PTR key;
LPOVERLAPPED pOverlapped = NULL;
if (!GetQueuedCompletionStatus(hPort, &rbytes, &key, &pOverlapped, INFINITE))
{
if (pOverlapped)
{
// WSARecvFrom() failed...
}
else
{
// GetQueuedCompletionStatus() failed...
}
// do something...
return;
}
}
// I/O complete, use buffer, dwBytesRecvd, dwFlags, and fromaddr as needed...
}
However, this defeats the purpose of IOCP. If you really want to be synchronous, you could just use recvfrom() instead and let it block the calling thread until data arrives. IOCP works best when you have a pool of threads servicing the completion port. Call WSARecvFrom() and let it work in the background, don't wait on it. Let a separate thread call GetQueuedCompletionPort() and process the data when it is received, eg:
struct MyOverlapped
{
WSAOVERLAPPED overlapped;
BYTE buffer[0xFFFF];
DWORD buflen;
DWORD flags;
sockaddr_storage fromaddr;
int fromaddrLen;
};
HANDLE hPort = NULL;
void foo() {
...
SOCKET sck = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (sck == INVALID_SOCKET)
{
// error, do something...
return;
}
....
bind(sck,(struct sockaddr *)&addr, sizeof(struct sockaddr_in));
hPort = CreateIoCompletionPort((HANDLE)sck, NULL, 0, 0 );
if (!hPort)
{
// error, do something...
return;
}
MyOverlapped *ov = new MyOverlapped;
ZeroMemory(ov, sizeof(*ov));
ov->overlapped.hEvent = WSACreateEvent();
ov->fromaddrlen = sizeof(ov->fromaddr);
WSABUF buf;
buf.len = sizeof(ov->buffer);
buf.buf = ov->buffer;
int iRet = WSARecvFrom(sck, &buf, 1, &ov->buflen, &ov->flags, (sockaddr*)&ov->fromaddr, &ov->fromaddrlen, (WSAOVERLAPPED*)ov, NULL);
if (iRet == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
// error, do something...
return;
}
// WSARecvFrom() is now operating in the background,
// the IOCP port will be signaled when finished...
}
else
{
// data is already available,
// the IOCP port will be signaled immediately...
}
...
}
...
// in another thread...
{
...
DWORD rbytes;
ULONG_PTR key;
MyOverlapped *ov = NULL;
if (!GetQueuedCompletionStatus(hPort, &rbytes, &key, (LPOVERLAPPED*)&ov, INFINITE))
{
if (ov)
{
// WSARecvFrom() failed...
// free ov, or reuse it for another operation...
}
else
{
// GetQueuedCompletionStatus() failed...
}
}
else
{
// use ov as needed...
// free ov, or reuse it for another operation...
}
...
}

Can someone explain what possible datatype this mean?

Can someone explain what possible datatype this refers to?
void (*sa_handler)(int)
from signal's man page.
It is a signal handler function in UNIX.
You declare it and then pass it to sigaction() system call.
Here untested code to catch USR1 signal which you can send to you process with kill command:
void my_function(int signal) {
continue_looping = 0;
}
volatile int continue_looping = 1;
int main(void) {
struct sigaction sa;
sigset_t mask;
sa.sa_handler = &my_function;
sa.sa_flags = SA_RESETHAND;
sigfillset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, NULL);
while(continue_looping) {
printf("Hello world\n");
}
return 0;
}
You should be careful when calling any further functions from your action handler. I usually just set a flag there - as in the above example.

FMOD pcmreadcallback never is called while playing audio from a microphone source

I'm writing a Unity class to capture and playback audio data from a microphone. Playback part works fine I can hear my voice in the headphones but I cannot access audio samples because pcmsetposcallback is never called during playback. It is called only once inside createSound method. I think i'm missing some setting , also tried several OR combinations for FMOD.MODE flag but with no luck.
I'm using fmodstudio10510.unitypackage and testing under windows 7 but it should have fully croos-platform support.
Thanks in advance.
Walter
public class AudioInit : MonoBehaviour {
FMOD.System lowlevel = null;
FMOD.Sound snd = null;
// callbacks delegates
FMOD.SOUND_PCMREADCALLBACK pcmreadcallbackPtr = new FMOD.SOUND_PCMREADCALLBACK (pcmreadcallbackFunc);
int driverId;
void Start () {
int channels = 1;
int sampleRate = 8000;
float recordTime = 1.0f;
// get low level instance
FMOD_StudioSystem.instance.System.getLowLevelSystem(out lowlevel);
// fill sound info struct
FMOD.CREATESOUNDEXINFO soundInfo = new FMOD.CREATESOUNDEXINFO ();
soundInfo.cbsize = System.Runtime.InteropServices.Marshal.SizeOf (typeof(FMOD.CREATESOUNDEXINFO));
soundInfo.length = (uint)(sampleRate * channels * sizeof(byte) * recordTime);
soundInfo.numchannels = channels;
soundInfo.defaultfrequency = sampleRate;
soundInfo.format = FMOD.SOUND_FORMAT.PCM8;
soundInfo.pcmreadcallback = pcmreadcallbackPtr;
soundInfo.pcmsetposcallback = pcmsetposcallbackPtr;
soundInfo.dlsname = IntPtr.Zero;
// FMODE MODE flag
FMOD.MODE mode = FMOD.MODE.OPENUSER | FMOD.MODE.LOOP_NORMAL;
// create sound
FMOD.RESULT res = lowlevel.createSound((string)null, mode, ref soundInfo, out snd);
if (res != FMOD.RESULT.OK) {
Debug.Log ("ERROR snd " + res.ToString ());
return;
}
// get driver
res = lowlevel.getDriver (out driverId);
if (res != FMOD.RESULT.OK) {
Debug.Log ("ERROR getDriver " + res.ToString ());
return;
}
// start record from microphone
res = lowlevel.recordStart (driverId, snd, true);
if (res != FMOD.RESULT.OK) {
Debug.Log ("ERROR recordStart " + res.ToString ());
return;
}
uint pos = 0;
uint tries = 10;
// wait for a valid record position
while ( !(pos > 0) && (tries--) > 0 ) {
if ( lowlevel.getRecordPosition(driverId, out pos) == FMOD.RESULT.OK ){
System.Threading.Thread.Sleep(100);
} else { break; }
}
if ( !( pos > 0 )) {
Debug.Log ("ERROR invalid record position");
return;
}
// start playback
FMOD.Channel chn;
res = lowlevel.playSound (snd, new FMOD.ChannelGroup (IntPtr.Zero), false, out chn);
if (res != FMOD.RESULT.OK) {
Debug.Log ("ERROR recordStart " + res.ToString ());
return;
}
}
// only called once during lowlevel.createSound execution
static FMOD.RESULT pcmreadcallbackFunc (IntPtr sound, IntPtr data, uint len){
Debug.Log("pcmreadcallback sample size " + len.ToString());
return FMOD.RESULT.OK;
}
// Update is called once per frame
void Update () {
}
}
The recording system doesn't go via pcmreadcallback, that's why you aren't getting those callbacks.
To access the microphone data use Sound::lock and Sound::unlock.