Using multiple audio input devices with AVAudioEngine - audiounit

I've got several usb audio input devices connected and I want to select more than 1 of them to connect to the mixer. The way I understand it, it will not be able to use AVAudioInputNode for this purpose.
I could accomplish this by using AVFoundation to read samples from each device and then schedule them to a player but it seems to me that this might be easier done with AVAudioUnit. Unfortunately, I have not been able to make that work.
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
[AVAudioUnit
instantiateWithComponentDescription:desc
options:kAudioComponentInstantiation_LoadInProcess
completionHandler:^(AVAudioUnit *xx, NSError *error) {
AudioUnitSetProperty(xx.audioUnit, kAudioOutputUnitProperty_CurrentDevice,
kAudioUnitScope_Global, 0, &inputDeviceID, sizeof(inputDeviceID));
[_engine attachNode:xx];
AVAudioMixerNode *mixer = [_engine mainMixerNode];
[_engine connect:xx to:mixer format:[xx outputFormatForBus:0]];
}];
[central] 54: ERROR: >avae> AVAudioEngineGraph.mm:1235: AddNode:
required condition is false: inImpl != nil && !IsIONode(inAVNode)
Any suggestions would be appreciated.

Related

Set DateTime SONY SDK

I am trying to set the datetime of a Sony RX0 II using the Sony SDK. Without modifying too much to the RemoteCli.cpp code that is provided as an example, I added a case there and create a new function in CameraDevice.cpp like this one
void CameraDevice::set_datetime()
{
// Set the new date at 1970/01/01
CrInt64 newdate = 0;
SDK::CrDeviceProperty prop;
prop.SetCode(SDK::CrDevicePropertyCode::CrDeviceProperty_DateTime_Settings);
prop.SetCurrentValue(newdate);
prop.SetValueType(SDK::CrDataType::CrDataType_UInt64);
auto err = SDK::SetDeviceProperty(m_device_handle, &prop);
if (CR_FAILED(err)) {
tout << "Failed to set new date path.\n";
}
I do not get any error, so it should work but I never got the new time written on the camera

Multiple USB to RS485 FTDI Device ID

I need some help. I'm programming a Win 10 App in C++/CX. I am using two USB to RS485 devices, both of which have the same VID number. In days of old, I could write a bit software and connect to ports using good old COMx etc.
I'm now following the example here Serial Sample which uses the approach gathering the device info so when looking for connected devices, what I see in the list of available devices is the following.
\?\FTDIBUS#VID_0403+PID_6001
Both devices have the same VID and PID. This leads to the problem of me being cable to connect to the correct USB device. I think my app is trying to connect to both devices at the same time? Does anyone have any ideas about how I can resolve this hitch?
void MainPage::Get_Serial_Devices() {
cancellationTokenSource_Port1 = new Concurrency::cancellation_token_source();
cancellationTokenSource_Port2 = new Concurrency::cancellation_token_source();
// THIS USES ASYNCRONOUS OPERATION. GET A LIST OF SERIAL DEVICES AND POPULATE THE COMBO BOX
Concurrency::create_task(ListAvailablePortsAsync()).then([this](DeviceInformationCollection^ serialDeviceCollectioin)
{
// serialDeviceCollection CONTAINS ALL SERIAL DEVICES FOUND, COPY INTO _deviceCollection
DeviceInformationCollection^ _deviceCollection = serialDeviceCollectioin;
// CLEAR EXISTING DEVICES FOR OUR OBJECT COLLECTION
_availableDevices->Clear();
// FOR EVERY DEVICE IN _deviceCollection
for (auto &&device : _deviceCollection) {
if (device->Name->Equals("USB-RS485 Cable")) {
// CREATE A NEW DEVICE TYPE AND APPEND TO OUR OBJECT COLLECTION
_availableDevices->Append(ref new Device(device->Id, device));
Total_Ports++;
this->DeviceLists->Items->Append(device->Id);
}
}
});
void MainPage::ConnectButton_Click(Object^ sender, RoutedEventArgs^ e) {
if (Port1_Connected == false) {
// CAST INDEX TO CORRELATING Device IN _availableDevices
Device^ selectedDevice = static_cast<Device^>(_availableDevices->GetAt(Port_1_ID));
// GET THE DEVICE INFO
DeviceInformation^ entry = selectedDevice->DeviceInfo;
Concurrency::create_task(ConnectToSerialDeviceAsync_Port1(entry, cancellationTokenSource_Port1->get_token())).then([this]( ) {
Get_Echo();
Waiting_For_Ack = true;
});
}
Concurrency::task<void> MainPage::ConnectToSerialDeviceAsync_Port1(DeviceInformation^ device, Concurrency::cancellation_token cancellationToken) {
// CREATE A LINKED TOKEN WHICH IS CANCELLED WHEN THE PROVIDED TOKEN IS CANCELLED
auto childTokenSource = Concurrency::cancellation_token_source::create_linked_source(cancellationToken);
// GET THE TOKEN
auto childToken = childTokenSource.get_token();
// CONNECT TO ARDUINO TASK
return Concurrency::create_task(SerialDevice::FromIdAsync(device->Id), childToken).then([this](SerialDevice^ serial_device) {
try {
_serialPort_Port1 = serial_device;
TimeSpan _timeOut; _timeOut.Duration = 10;
// CONFIGURE SERIAL PORT SETTINGS
_serialPort_Port1->WriteTimeout = _timeOut;
_serialPort_Port1->ReadTimeout = _timeOut;
_serialPort_Port1->BaudRate = 57600;
_serialPort_Port1->Parity = Windows::Devices::SerialCommunication::SerialParity::None;
_serialPort_Port1->StopBits = Windows::Devices::SerialCommunication::SerialStopBitCount::One;
_serialPort_Port1->DataBits = 8;
_serialPort_Port1->Handshake = Windows::Devices::SerialCommunication::SerialHandshake::None;
// CREATE OUR DATA READER OBJECT
_dataReaderObject_Port1 = ref new DataReader(_serialPort_Port1->InputStream);
_dataReaderObject_Port1->InputStreamOptions = InputStreamOptions::None;
// CREATE OUR DATA WRITE OBJECT
_dataWriterObject_Port1 = ref new DataWriter(_serialPort_Port1->OutputStream);
this->ConnectButton->IsEnabled = false;
this->DisconnectButton->IsEnabled = true;
// KICK OF THE SERIAL PORT LISTENING PROCESS
Listen_Port1();
}
catch (Platform::Exception^ ex) {
this->Error_Window->Text = (ex->Message);
CloseDevice(PORT_1);
}
});
FT_PROG is a free EEPROM programming utility for use with FTDI devices. It is used for modifying EEPROM contents that store the FTDI device descriptors to customize designs.
The full FT_PROG User Guide can be downloaded here.

AVAssetExportSession make black video sometimes

I'm new baby for Video Processing use Swift 3. I try to merge multiple videos with AVAssetExportSession, and using AVVideoCompositionCoreAnimationTool to add overlay for final video.
The problem is sometimes the final video is perfect, but sometimes it just give me a black video with sound only even I didn't change anything :(
Anybody who ran into that problem same me please give an idea, thanks!
let mixComposition: AVMutableComposition = AVMutableComposition()
//Add assets here
let mainComposition: AVMutableVideoComposition = AVMutableVideoComposition(propertiesOf: mixComposition)
mainComposition.frameDuration = CMTimeMake(1, 30)
mainComposition.renderSize = renderSize
mainComposition.renderScale = 1.0
mainComposition.animationTool = AVVideoCompositionCoreAnimationTool(postProcessingAsVideoLayer: videoLayer, in: parentLayer)
mainComposition.instructions = instructions
let exportSession: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)!
exportSession.videoComposition = mainComposition
exportSession.audioMix = audioMix
exportSession.outputURL = outputURL
exportSession.outputFileType = AVFileTypeMPEG4
exportSession.shouldOptimizeForNetworkUse = true
exportSession.exportAsynchronously {
// Ended here
}

openh264 - bEnableFrameSkip=0, bitrate can't be controlled

there are a lot of questions asked regarding opencv + H.264 but
none of them gave detailed explanation.
i am using openh264(openh264-1.4.0-win32msvc.dll) along with opencv 3.1(custom build with cmake having ffmpeg enabled) in visual studio, i wanted to save video coming from webcam in mp4 format with H.264 compression
VideoWriter write = VideoWriter("D:/movie.mp4", CV_FOURCC('H', '2',
'6', '4'), 10.0, cv::Size(192, 144), true);
before using openh264, in console window i was seeing an warning message
"Failed to load openh264 library : openh264-1.4.0-win32msvc.dll
please check your environment and/or download from here:
https://github.com/cisco/openh264/releases"
(also video was not been saved)
so i downloaded the dll & kept in a folder with my program file(exe)
now when i run the program, i'm seeing different error
"[OpenH264] this = 0x0DE312C0, warning: bEnabledFrameSkip=0, bitrate can't be controlled for RC_QUALITY_MODE and RC_TIMESTAMP_MODE without enabling skip frame"
(now video is saved, but size is very high! bit rate is around 1200 Kbps)
for me, the sole purpose of using h264 is to reduce the file size.. i think i may have to build openh264 myself with some changes to remove this error, can anyone guide me how? or tell me if there is a way to reduce bit rate somehow through code?
P.S: I tried giving -1 instead of CV_FOURCC(), 'installed codecs' window in my system showed up, i couldn't find h264 or x264 or h264vfw even though i have installed variety of codec packs & h264 from here
Thanks & regards
If you want to control bitrate, You have to use both
encoderParemeters.iRCMode = RC_OFF_MODE;
encoderParemeters.bEnableFrameSkip = true;
Here I am showing all the Openh264 Encoding parameters as an Example:
long nReturnedValueFromEncoder = WelsCreateSVCEncoder(&m_pSVCVideoEncoder);
m_nVideoWidth = 352;
m_nVideoHeight = 288;
SEncParamExt encoderParemeters;
memset(&encoderParemeters, 0, sizeof(SEncParamExt));
m_pSVCVideoEncoder->GetDefaultParams(&encoderParemeters);
encoderParemeters.iUsageType = CAMERA_VIDEO_REAL_TIME;
encoderParemeters.iTemporalLayerNum = 0;
encoderParemeters.uiIntraPeriod = 15;
encoderParemeters.eSpsPpsIdStrategy = INCREASING_ID;
encoderParemeters.bEnableSSEI = false;
encoderParemeters.bEnableFrameCroppingFlag = true;
encoderParemeters.iLoopFilterDisableIdc = 0;
encoderParemeters.iLoopFilterAlphaC0Offset = 0;
encoderParemeters.iLoopFilterBetaOffset = 0;
encoderParemeters.iMultipleThreadIdc = 0;
encoderParemeters.iRCMode = RC_BITRATE_MODE;
encoderParemeters.iMinQp = 0;
encoderParemeters.iMaxQp = 52;
encoderParemeters.bEnableDenoise = false;
encoderParemeters.bEnableSceneChangeDetect = false;
encoderParemeters.bEnableBackgroundDetection = true;
encoderParemeters.bEnableAdaptiveQuant = false;
encoderParemeters.bEnableFrameSkip = true;
encoderParemeters.bEnableLongTermReference = true;
encoderParemeters.iLtrMarkPeriod = 20;
encoderParemeters.bPrefixNalAddingCtrl = false;
encoderParemeters.iSpatialLayerNum = 1;
SSpatialLayerConfig *spartialLayerConfiguration = &encoderParemeters.sSpatialLayers[0];
spartialLayerConfiguration->uiProfileIdc = PRO_BASELINE;//;
encoderParemeters.iPicWidth = spartialLayerConfiguration->iVideoWidth = m_nVideoWidth;
encoderParemeters.iPicHeight = spartialLayerConfiguration->iVideoHeight = m_nVideoHeight;
encoderParemeters.fMaxFrameRate = spartialLayerConfiguration->fFrameRate = (float)30;
encoderParemeters.iTargetBitrate = spartialLayerConfiguration->iSpatialBitrate = 500000;
encoderParemeters.iTargetBitrate = spartialLayerConfiguration->iMaxSpatialBitrate = 500000;
spartialLayerConfiguration->iDLayerQp = 24;
//spartialLayerConfiguration->sSliceCfg.uiSliceMode = SM_SINGLE_SLICE;
spartialLayerConfiguration->sSliceArgument.uiSliceMode = SM_SINGLE_SLICE;
nReturnedValueFromEncoder = m_pSVCVideoEncoder->InitializeExt(&encoderParemeters);
Hope it will help you.
You can simply controlled bit rate using RC_BITRATE_MODE and enabling bEnableFrameSkip in Openh264.

List device-names available for video capture from ksvideosrc in gstreamer 1.0

I am trying to query a list of available video capture devices (webcams) on windows using gstreamer 1.0 in c++.
I am using ksvideosrc as source and i am able to capture the video input but i can't query a list of available devices (and their caps).
On gstreamer 0.10 it has been possible through GstPropertyProbe which is removed in gstreamer 1.0. The documentation suggests using GstDeviceMonitor. But i have no luck using that either.
Has anyone succeeded in acquiring a list of device names? Or can you suggests another way of retrieving the available device names and their caps?
You can use GstDeviceMonitor and gst_device_monitor_get_devices () function.
First initialize GstDeviceMonitor by gst_device_monitor_new().
Second start the monitor by gst_device_monitor_start(pMonitor).
Third, get devices list by gst_device_monitor_get_devices(pMonitor).
Code would be like this:
GstDeviceMonitor* monitor= gst_device_monitor_new();
if(!gst_device_monitor_start(monitor)){
printf("WARNING: Monitor couldn't started!!\n");
}
GList* devices = gst_device_monitor_get_devices(monitor);
My references:
https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer/html/gstreamer-GstDeviceMonitor.html#gst-device-monitor-get-devices
Although I haven't figured out how to enumerate the device names, I've come up with a workaround to at least get the available ksvideosrc device indexes. Below is the code in Python, but you should be able to port it to C++ fairly easily, thanks to the GObject introspection bindings.
from gi.repository import Gst
def get_ksvideosrc_device_indexes():
device_index = 0
video_src = Gst.ElementFactory.make('ksvideosrc')
state_change_code = None
while True:
video_src.set_state(Gst.State.NULL)
video_src.set_property('device-index', device_index)
state_change_code = video_src.set_state(Gst.State.READY)
if state_change_code != Gst.StateChangeReturn.SUCCESS:
video_src.set_state(Gst.State.NULL)
break
device_index += 1
return range(device_index)
if __name__ == '__main__':
Gst.init()
print get_ksvideosrc_device_indexes()
Note that the video source device-name property is None as of GStreamer version 1.4.5.0 on Windows for the ksvideosrc.
It's very late, but for the future...
The Gst.DeviceMonitor can be used to enumerate devices, and register an addition or removal of a device.
Here's how to get device names in C# with GStreamer 1.14
static class Devices
{
public static void Run(string[] args)
{
Application.Init(ref args);
GtkSharp.GstreamerSharp.ObjectManager.Initialize();
var devmon = new DeviceMonitor();
// to show only cameras
// var caps = new Caps("video/x-raw");
// var filtId = devmon.AddFilter("Video/Source", caps);
var bus = devmon.Bus;
bus.AddWatch(OnBusMessage);
if (!devmon.Start())
{
"Device monitor cannot start".PrintErr();
return;
}
Console.WriteLine("Video devices count = " + devmon.Devices.Length);
foreach (var dev in devmon.Devices)
DumpDevice(dev);
var loop = new GLib.MainLoop();
loop.Run();
}
static void DumpDevice(Device d)
{
Console.WriteLine($"{d.DeviceClass} : {d.DisplayName} : {d.Name} ");
}
static bool OnBusMessage(Bus bus, Message message)
{
switch (message.Type)
{
case MessageType.DeviceAdded:
{
var dev = message.ParseDeviceAdded();
Console.WriteLine("Device added: ");
DumpDevice(dev);
break;
}
case MessageType.DeviceRemoved:
{
var dev = message.ParseDeviceRemoved();
Console.WriteLine("Device removed: ");
DumpDevice(dev);
break;
}
}
return true;
}
}