Extra Sound Device Hotplug Problem

SG
Shany Guetta
Wed, Nov 14, 2018 3:22 PM

Hello,

I am trying to develop a pjsip app which will manage more usb sound devices
concurrently.
I am using PJSIP 2.8 .
I am trying to manage the case in which a device is disconnected by fault
at runtime and reconnected again without restarting the application.

What I do today is at the startup I start a timer and at each timeout I
call :

AudDevManager& mgr = Endpoint::instance().audDevManager();

mgr.refreshDevs();

I iterate over the available devices and if I didn't create them
before I create them in this way:

bool VCSSoundDevMgr::createAudioDevice(int deviceID, AudioDevInfo info)

{

try

{

    pj_status_t status;

    pjsua_ext_snd_dev * snd_dev;

    /* Generate sound device port param */

    pjmedia_snd_port_param param;

    pjmedia_snd_port_param_default(&param);

    status = pjmedia_aud_dev_default_param(deviceID, &param.base);

    if(status!= PJ_SUCCESS)

    {

        qDebug()<<"VCSSoundDevMgr::createAudioDevice -

pjmedia_aud_dev_default_param error";

    }


    param.base.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;

    param.base.play_id = deviceID;

    param.base.rec_id = deviceID;

    param.base.clock_rate = master_info.clock_rate;

    param.base.channel_count = master_info.channel_count;

    param.base.samples_per_frame = master_info.samples_per_frame;

    param.base.bits_per_sample = master_info.bits_per_sample;


    status = pjsua_ext_snd_dev_create(&param, &snd_dev);

    if(status!= PJ_SUCCESS)

    {

       qDebug()<<"VCSSoundDevMgr::createAudioDevice - cannot

create device:"<<deviceID;

}

    else

    {

        int slotID = pjsua_ext_snd_dev_get_conf_port(snd_dev);

        AudioDeviceInfo *s = new AudioDeviceInfo();

        QString devName = QString::fromStdString(info.name);

        s->device = snd_dev;

        s->info = info;

        s->slot = slotID;

        s->friendly_name = mDeviceNames.value(devName,devName);

        mAudioDevices.insert(devName, s);

        qDebug()<<"VCSSoundDevMgr::createAudioDevice - created

Sound Dev:"<<devName<<" ID:"<<deviceID<<" slot:"<<slotID;

    }

}

catch(Error &err)

{

    qDebug()<<"VCSSoundDevMgr::createSoundDeviceSlot() - error:"

           << err.info().c_str();

  return false;

}

return true;

}

At each timeout i also iterate over the devices already created to
check if they are still connected simply by calling :

bool VCSSoundDevMgr::isDeviceConnected(QString name)

{

AudDevManager& mgr = Endpoint::instance().audDevManager();

try

{

    mgr.lookupDev("ALSA", name.toStdString());

    return true;

}

catch (Error& e)

{

    return false;

}

}

In case it is disconnected, I create a thread to destroy the sound
device in this way:

void VCSSoundDevMgr::destroyAudioDevice(AudioDeviceInfo *info)

{

qDebug()<<"Destroying device..";

pj_status_t status;

try

{

    AudioMediaVector vector = Endpoint::instance().mediaEnumPorts();

    foreach(AudioMedia * media, vector)

    {

        if(media->getType() == PJMEDIA_TYPE_AUDIO)

        {

            pjsua_conf_disconnect(media->getPortId(), info->slot);

            pjsua_conf_disconnect(info->slot, media->getPortId());

        }

    }

    qDebug()<<"Disconnected calls..";


    pj_pool_t	*pool = pjsua_pool_create("pool",4000,4000);

    pj_thread_t *pjThread;

    //CREATE THREAD

    status = pj_thread_create (pool,

                               "soundevmgr_destroy",

                               threadDestroy,

                               info->device,

                               0, //ZERO,

                               0,

                               &pjThread);

    if (status != PJ_SUCCESS)

    {

        qDebug() << "VCSSoundDevMgr::destroySoundDevices() -

WARNING: pj_thread_create is not created.";

        pj_thread_join(pjThread);

        pj_thread_destroy(pjThread);

    }


    mAudioDevices.remove(QString::fromStdString(info->info.name));

    delete info;

    info = NULL;

    qDebug()<<"DEVICE DELETED";

}catch(Error &err)

{

    qDebug() << "VCSSoundDevMgr::destroyAudioDevice() - ERROR: "

             << err.info().c_str();

}

}

static int threadDestroy (void *arg)

{

/* Check if we have sound stream device. */

pj_status_t status;

//REGISTERING THREAD

pj_thread_desc aPJThreadDesc;

pj_thread_t *pjThread;

if (!pj_thread_is_registered()) {

    status = pj_thread_register("soundevmgr_destroy",

aPJThreadDesc, &pjThread);

    qDebug()<<"VCSSoundDevMgr::destroySoundDevices() - registered thread";

    if (status != PJ_SUCCESS) {

        qDebug() << "VCSSoundDevMgr::destroySoundDevices() -

WARNING: pjthread is not registered.";

    }

}

pjsua_ext_snd_dev * dev = (pjsua_ext_snd_dev *)arg;

status = pjsua_ext_snd_dev_destroy(dev);

if(status != PJ_SUCCESS)

{

    qDebug() << "VCSSoundDevMgr::destroyAudioDevice - "

             << "pjsua_ext_snd_dev_destroy  error";

}

qDebug()<<"THREAD TERMINATED..";

return PJ_SUCCESS;

}

Until here, everything works great!
I turn on the application, the devices are created, I disconnect a device
from the USB, the application destroy the sound device.
MY PROBLEM COMES NOW:
When I plug-in the device that I previously disconnected the
AudioDeviceManager sees the device, try to create it but this step in the
creation returns an error:

status = pjmedia_aud_dev_default_param(deviceID, &param.base);

And the device cannot be created because it results it has zero output
and zero input count.

Basically after some investigation I think that alsa_dev.c is setting
those counts to zero because

it fails to do snd_pcm_open on this device. But how come at the
beginning it was possible to open it and when I plug it in again not?

Is there any one that can help me understand why this happens?

Thanks in advance.

Shani

Hello, I am trying to develop a pjsip app which will manage more usb sound devices concurrently. I am using PJSIP 2.8 . I am trying to manage the case in which a device is disconnected by fault at runtime and reconnected again without restarting the application. What I do today is at the startup I start a timer and at each timeout I call : ## AudDevManager& mgr = Endpoint::instance().audDevManager(); mgr.refreshDevs(); ## I iterate over the available devices and if I didn't create them before I create them in this way: ## bool VCSSoundDevMgr::createAudioDevice(int deviceID, AudioDevInfo info) { try { pj_status_t status; pjsua_ext_snd_dev * snd_dev; /* Generate sound device port param */ pjmedia_snd_port_param param; pjmedia_snd_port_param_default(&param); status = pjmedia_aud_dev_default_param(deviceID, &param.base); if(status!= PJ_SUCCESS) { qDebug()<<"VCSSoundDevMgr::createAudioDevice - pjmedia_aud_dev_default_param error"; } param.base.dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; param.base.play_id = deviceID; param.base.rec_id = deviceID; param.base.clock_rate = master_info.clock_rate; param.base.channel_count = master_info.channel_count; param.base.samples_per_frame = master_info.samples_per_frame; param.base.bits_per_sample = master_info.bits_per_sample; status = pjsua_ext_snd_dev_create(&param, &snd_dev); if(status!= PJ_SUCCESS) { qDebug()<<"VCSSoundDevMgr::createAudioDevice - cannot create device:"<<deviceID; } else { int slotID = pjsua_ext_snd_dev_get_conf_port(snd_dev); AudioDeviceInfo *s = new AudioDeviceInfo(); QString devName = QString::fromStdString(info.name); s->device = snd_dev; s->info = info; s->slot = slotID; s->friendly_name = mDeviceNames.value(devName,devName); mAudioDevices.insert(devName, s); qDebug()<<"VCSSoundDevMgr::createAudioDevice - created Sound Dev:"<<devName<<" ID:"<<deviceID<<" slot:"<<slotID; } } catch(Error &err) { qDebug()<<"VCSSoundDevMgr::createSoundDeviceSlot() - error:" << err.info().c_str(); return false; } return true; } ## At each timeout i also iterate over the devices already created to check if they are still connected simply by calling : ## bool VCSSoundDevMgr::isDeviceConnected(QString name) { AudDevManager& mgr = Endpoint::instance().audDevManager(); try { mgr.lookupDev("ALSA", name.toStdString()); return true; } catch (Error& e) { return false; } } ## In case it is disconnected, I create a thread to destroy the sound device in this way: ## void VCSSoundDevMgr::destroyAudioDevice(AudioDeviceInfo *info) { qDebug()<<"Destroying device.."; pj_status_t status; try { AudioMediaVector vector = Endpoint::instance().mediaEnumPorts(); foreach(AudioMedia * media, vector) { if(media->getType() == PJMEDIA_TYPE_AUDIO) { pjsua_conf_disconnect(media->getPortId(), info->slot); pjsua_conf_disconnect(info->slot, media->getPortId()); } } qDebug()<<"Disconnected calls.."; pj_pool_t *pool = pjsua_pool_create("pool",4000,4000); pj_thread_t *pjThread; //CREATE THREAD status = pj_thread_create (pool, "soundevmgr_destroy", threadDestroy, info->device, 0, //ZERO, 0, &pjThread); if (status != PJ_SUCCESS) { qDebug() << "VCSSoundDevMgr::destroySoundDevices() - WARNING: pj_thread_create is not created."; pj_thread_join(pjThread); pj_thread_destroy(pjThread); } mAudioDevices.remove(QString::fromStdString(info->info.name)); delete info; info = NULL; qDebug()<<"DEVICE DELETED"; }catch(Error &err) { qDebug() << "VCSSoundDevMgr::destroyAudioDevice() - ERROR: " << err.info().c_str(); } } static int threadDestroy (void *arg) { /* Check if we have sound stream device. */ pj_status_t status; //REGISTERING THREAD pj_thread_desc aPJThreadDesc; pj_thread_t *pjThread; if (!pj_thread_is_registered()) { status = pj_thread_register("soundevmgr_destroy", aPJThreadDesc, &pjThread); qDebug()<<"VCSSoundDevMgr::destroySoundDevices() - registered thread"; if (status != PJ_SUCCESS) { qDebug() << "VCSSoundDevMgr::destroySoundDevices() - WARNING: pjthread is not registered."; } } pjsua_ext_snd_dev * dev = (pjsua_ext_snd_dev *)arg; status = pjsua_ext_snd_dev_destroy(dev); if(status != PJ_SUCCESS) { qDebug() << "VCSSoundDevMgr::destroyAudioDevice - " << "pjsua_ext_snd_dev_destroy error"; } qDebug()<<"THREAD TERMINATED.."; return PJ_SUCCESS; } ## Until here, everything works great! I turn on the application, the devices are created, I disconnect a device from the USB, the application destroy the sound device. MY PROBLEM COMES NOW: When I plug-in the device that I previously disconnected the AudioDeviceManager sees the device, try to create it but this step in the creation returns an error: status = pjmedia_aud_dev_default_param(deviceID, &param.base); And the device cannot be created because it results it has zero output and zero input count. Basically after some investigation I think that alsa_dev.c is setting those counts to zero because it fails to do snd_pcm_open on this device. But how come at the beginning it was possible to open it and when I plug it in again not? Is there any one that can help me understand why this happens? Thanks in advance. Shani