Configuring multiple devices in PortAudio: Invalid device error - portaudio

This query is regarding the Portaudio framework. A little background before I ask the question:I am working on an application in PortAudio to output audio through a multichannel(=8) device. However, the device I am using does not expose itself as a single 8-channel device but instead shows up in my device-list as 4 stereo devices. On searching for an approach to handle this, I got to know that WinMME in PortAudio supports multiple devices.
Now, I went through the appropriate header file("pa_win_wmme.h") and followed the suggestions present. But I get the 'Invalid device' error (error number -9996) after calling PA_OpenStream(). In the above mentioned header file, they have in fact specified the right parameter(s) to use when configuring multiple devices to avoid this error, but in-spite of following them, I still get the error.
So I wanted to know if anybody has faced a similar issue and whether I have missed/wrongly configured anything.
I am pasting the required snippets of code below for reference:
PaStreamParameters outputParameters;
PaWinMmeStreamInfo wmmeStreamInfo;
PaWinMmeDeviceAndChannelCount wmmeDeviceAndNumChannels;**
...
...
outputParameters.device = paUseHostApiSpecificDeviceSpecification;
outputParameters.channelCount = 8;
outputParameters.sampleFormat = paFloat32; /* 32 bit floating point processing */
outputParameters.hostApiSpecificStreamInfo = NULL;
wmmeStreamInfo.size = sizeof(PaWinMmeStreamInfo);
wmmeStreamInfo.hostApiType = paMME;
wmmeStreamInfo.version = 1;
wmmeStreamInfo.flags = paWinMmeUseMultipleDevices;
wmmeDeviceAndNumChannels.channelCount = 2;
wmmeDeviceAndNumChannels.device = 3;
wmmeStreamInfo.devices = &wmmeDeviceAndNumChannels;
wmmeStreamInfo.deviceCount = 4;
outputParameters.hostApiSpecificStreamInfo = &wmmeStreamInfo;
The device id = 3 was obtained through
Pa_GetHostApiInfo( Pa_HostApiTypeIdToHostApiIndex( paMME ) )->defaultOutputDevice
I hope I have made the query clear enough. Will be happy to provide more details if required.
Thanks.

I finally figured out the mistake :-)
The configuration for multiple devices must be made as an array. For instance, in the above case
wmmeDeviceAndNumChannels must be an array of 4, with each individual device field containing the corresponding device index of each of the 4 stereo devices. The channelCount remains 2. The outputParameters.channelCount still has to be the aggregate number of channels, i.e. 8. With this I was able to run the application with a single stream, and of course, without any errors related to invalid device or invalid number of channels.:-)
Thanks.

Based on the code pasted above, it looks like you are trying to call open on a single 8-channel device. Instead you will have to get the Pa index of all four devices and call open 4 times. Once for each stereo device. You will then have 4 interleaved stereo streams to maintain. My guess is that changing channelCount = 8 to channelCount = 2 will allow the first stream to open.

Related

UIVideoEditorController videoQuality setting not working

I'm currently trying to use UIVideoEditorViewController to trim a video file previously selected from the Photos app by using UIImagePickerController. I verified that after choosing the file and before creating UIVideoEditorViewController the file has the original resolution. However, after trimming the video, the output is always in 360p resolution despite setting the videoQuality property to high. All the applicable settings seem to be ignored for this property and the video ends up being compressed unnecessarily.
I have found multiple people reporting similar issues but yet have to find a workaround for this.
let editor = UIVideoEditorController()
editor.delegate = self
editor.videoMaximumDuration = 0 // No limit for now
// TODO: This should really work, however while testing it seems like the imported videos are always scaled down
// to 320p which equivalents the default value of .low.
editor.videoQuality = .typeHigh
editor.videoPath = internalURL.path
Any help would be greatly appreciated.

How to use SpringboardServices to get notifications count of an app ios

How can I get notifications count of another app into my app by using SpringboardServices and SBSPushStore?
I'm trying to show notification count taken from whatsapp into my app so I was searching around and one thing is for sure that it is possible but I didn't find any approbate way on how to do it.Here is the question which answers it but I didn't get it. How to do it? Can someone please share the step by step procedure.
Based on the question I was able to find the code which can actually lock you iphone using SpringboardServices but I don't know how to use it for SBSPushStore?
void *SpringBoardServices = dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY);
NSParameterAssert(SpringBoardServices);
mach_port_t (*SBSSpringBoardServerPort)() = dlsym(SpringBoardServices, "SBSSpringBoardServerPort");
NSParameterAssert(SBSSpringBoardServerPort);
SpringBoardServicesReturn (*SBSLockDevice)(mach_port_t port) = dlsym(SpringBoardServices, "SBSLockDevice");
NSParameterAssert(SBSLockDevice);
mach_port_t sbsMachPort = SBSSpringBoardServerPort();
SBSLockDevice(sbsMachPort);
dlclose(SpringBoardServices);
The answer to that linked question you commented on implies that you don't need any framework, as long as your device is jailbroken.
You simply load the plist file located at /var/mobile/Library/SpringBoard/applicationState.plist. The format of that answer is a bit broken, but I assume the > are meant as indicators to explain the inner structure of the file (i.e. key values).
So from that I assume it's a dictionary, you can load it by
NSDictionary *plistFile = [NSDictionary dictionaryWithContentsOfFile:#"/var/mobile/Library/SpringBoard/applicationState.plist"];
NSDictionary *entryForYourApp = plistFile[#"com.app.identifier"]; // obviously you have to use the identifier of whatever app you wanna check
NSInteger badgeCount = entryForYourApp[#"SBApplicationBadgeKey"];
You probably want to inspect the file yourself first (so set a debug point) and make sure its structure is like I assumed, the types are correct and so forth (not to mention it exists, Apple sometimes changes stuff like that and the other question is already several years old).
In general be aware that you can only do that, as said, on a jailbroken device. Otherwise your application simply doesn't have reading access to the path /var/mobile/Library/SpringBoard/applicationState.plist. Or to anything outside its sandbox, for that matter.

Detect if Cycript/Substrate or gdb is attached to an iOS app's process?

I am building an iOS app that transmits sensitive data to my server, and I'm signing my API requests as an additional measure. I want to make reverse engineering as hard as possible, and having used Cycript to find signing keys of some real-world apps, I know it's not hard to find these keys by attaching to a process. I am absolutely aware that if someone is really skilled and tries hard enough, they eventually will exploit, but I'm trying to make it as hard as possible, while still being convenient for myself and users.
I can check for jailbroken status and take additional measures, or I can do SSL pinning, but both are still easy to bypass by attaching to the process and modifying the memory.
Is there any way to detect if something (whether it be Cycript, gdb, or any similar tool that can be used for cracking the process) is attached to the process, while not being rejected from App Store?
EDIT: This is not a duplicate of Detecting if iOS app is run in debugger. That question is more related to outputting and it checks an output stream to identify if there's an output stream attached to a logger, while my question is not related to that (and that check doesn't cover my condition).
gdb detection is doable via the linked stackoverflow question - it uses the kstat to determine if the process is being debugged. This will detect if a debugger is currently attached to the process.
There is also a piece of code - Using the Macro SEC_IS_BEING_DEBUGGED_RETURN_NIL in iOS app - which allows you to throw in a macro that performs the debugger attached check in a variety of locations in your code (it's C/Objective-C).
As for detecting Cycript, when it is run against a process, it injects a dylib into the process to deal with communications between the cycript command line and the process - the library has part of the name looking like cynject. That name doesn't look similar to any libraries that are present on a typical iOS app. This should be detectable with a little loop like (C):
BOOL hasCynject() {
int max = _dyld_image_count();
for (int i = 0; i < max; i++) {
const char *name = _dyld_get_image_name(i);
if (name != NULL) {
if (strstr(name, "cynject") == 0) return YES;
}
}
}
Again, giving it a better name than this would be advisable, as well as obfuscating the string that you're testing.
These are only approaches that can be taken - unfortunately these would only protect you in some ways at run-time, if someone chooses to point IDA or some other disassembler at it then you would not be protected.
The reason that the check for debugger is implemented as a macro is that you would be placing the code in a variety of places in the code, and as a result someone trying to fix it would have to patch the app in a variety of places.
Based on #petesh's answer, I found the below code achieved what I wanted on a jailbroken phone with Cycript. The existence of printf strings is gold to a reverse engineer, so this code is only suitable for demo / crack-me apps.
#include <stdio.h>
#include <string.h>
#include <mach-o/dyld.h>
int main ()
{
int max = _dyld_image_count();
for (int i = 0; i < max; i++) {
const char *name = _dyld_get_image_name(i);
const char needle[11] = "libcycript";
char *ret;
if ((ret = strstr(name, needle)) != NULL){
printf("%s\nThe substring is: %s\n", name, ret);
}
}
return 0;
}
As far as I know, Cycript process injection is made possible by debug symbols. So, if you strip out debug symbols for the App Store release (the default build setting for the Release configuration), that would help.
Another action you could take, which would have no impact on the usability of the App, would be to use an obfuscator. However, this would render any crash reports useless, since you wouldn't be able to make sense of the symbols, even if the crash report was symbolicated.

How to get current stream position using GoogleCast frameWork in iOS

I am working on an application in which I will connect to the T.V using ChromeCast device, to achieve this I have used GoogleCast FrameWork in my project,
I am facing a problem when I try to access the approximate stream position of the video using the below statements,
GCKMediaControlChannel *mediaControlChannel = [[GCKMediaControlChannel alloc] init];
NSLog(#"Approximate stream position is %f",mediaControlChannel.approximateStreamPosition);
But this is resulting in a time difference of 20 seconds.
I tried below statements to get the exact stream position,
GCKMediaStatus *deviceStatus = [[GCKMediaStatus alloc] initWithSessionID:sessionId mediaInformation:self.mediaInformation];
NSLog(#"Stream Position %f", self.deviceStatus.streamPosition);
As the above method is having two parameters,We need to send session as an integer, but we are getting session id as a string alpha numeric and upon converting this to integer resulting in 0.
Can any one help me to get the session ID as an integer, Or suggest me to get the current stream position with any different method.
I use the following code to retrieve the stream position of the video that is currently being casted, and it's pretty accurate! The Google Cast SDK version that we use in our project is 3.5.3.
let position = Double(GCKCastContext.sharedInstance().sessionManager.currentSession!.remoteMediaClient!.mediaStatus!.streamPosition)
Hope it helps!
approximateStreamPosition should give you a pretty accurate time, certainly not off by 20 seconds. You can take a look at our iOS reference app for an example.
You can use approximateStreamPosition for the same.
Below code will print the more accurate time.
if let position = GCKCastContext.sharedInstance().sessionManager.currentSession?.remoteMediaClient?.approximateStreamPosition() {
print("current time ",position)
}

App used to work with AIR 3.2, doesn't work with AIR 3.5

I'm getting this error when I press a button in a flash/air app that used to work in the AIR 3.2 SDK - now upgraded to the AIR 3.5 SDK. Any help much appreciated.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at seed_template_fla::MainTimeline/frame7()[seed_template_fla.MainTimeline::frame7:31]
at flash.display::MovieClip/gotoAndPlay()
at seed_template_fla::MainTimeline/gotoPage() [seed_template_fla.MainTimeline::frame1:20]
at seed_template_fla::MainTimeline/gotoRepro() [seed_template_fla.MainTimeline::frame1:12]
I'm creating an app for iPhone using Flash CS6 on Mac and exporting using the Air 3.5 SDK. I also have the AIR 3.5 runtime installed.
The app is very simple at the moment. It basically moves from frame to frame when you press a button using the gotoAndPlay(frameNr) function. There are some hexes on the frames that update an array of numbers when clicked. They are also toggled visible/not visible.
This used to work perfectly using the AIR 3.2 SDK, but I recently downloaded the AIR 3.5 SDK from adobe and added it through flash (Help>Manage Air SDK) and set it as the build target in File>Publish Settings>Target.
When I switch back to AIR 3.2 SDK, the app works perfectly again.
Also, when I upload the app to my iPhone 4S running IOS 5.1 using AIR 3.5 SDK, I just see a black screen with 5 loading dots flashing. This also works fine with AIR 3.2 SDK.
This is the code for frame 7
The last line is line 31.
stop();
techtitle.text = "Select Trait";
techdesc.text = "Spend points to change core stats and other special abilities";
points.visible = false;
techpoints.visible=false;
pointsbalance.text = myPoints.toString();
btn_tech.visible = false;
curTechSelected = null;
trace("set hexes invisible");
for (var j:int = 0; j <= 67; j++) {
if (hexStatusb[j] == 1) {
this["btn_hex_"+j+"b"].visible = false;
}
}
function onBtnHex37bClick(event:MouseEvent):void
{
techtitle.text = "tech1";
techdesc.text = "tech1 description"
techpoints.text = "-2";
points.visible = true;
techpoints.visible=true;
btn_tech.visible = true;
curTechSelected = btn_hex_37b;
curTechSelectedNr = 37;
curTechPoints = 2;
}
trace(this["btn_hex_37b"]);
btn_hex_37b.addEventListener(MouseEvent.CLICK, onBtnHex37bClick);
OK - so, after trying out lots of things, I figured out why this is happening.
Solution: get rid of all TFL text objects when running AIR 3.5 SDK
It seems that the TFL Text library wasn't being loaded properly at runtime. Something crucial that I neglected to mention was that I was getting this warning message (similar here http://forums.adobe.com/thread/825637)
Content will not stream... The runtime shared libraries being preloaded are textLayout_1.0.0.05... TFLText
and this warning message in the output
Warning: Ignoring 'secure' attribute in policy file from http://fpdownload.adobe.com/pub/swz/crossdomain.xml. The 'secure' attribute is only permitted in HTTPS and socket policy files.
Simply removing all TFLText objects and changing them to classic text makes the app work fine again.
#csomakk Great news. I have found the answer. You can publish in 3.5 and 3.6 and have your TLF Text too. I posted a write-up on my blog that shows exactly how to do it.
To get started: the error message states that something is null.. it means, that the program doesn't know, where to look for it. It can happen, when you didn't create the object (btn_hex_37b = new MovieClip()); or you haven't even created a variable for it.
on the given line (btn_hex_37b.addEventListener(MouseEvent.CLICK, onBtnHex37bClick);) only btn_hex_37b can be null, because onBtnHex37bClick exists, and if it wouldn't, the program wouldn't compile.
The reason it came up when switching to AIR 3.5 is probably that it calls some creation functions in different order. Go to the line where you define the btn_hex_37b variable. Search for that functions calling.. Make sure, that btn_hex_37b is created before going to frame7.
Also, if its not a vital, to have onBtn_hex_37bClick, you can do the following:
if(btn_hex_37b){
btn_hex_37b.addEventListener(MouseEvent.CLICK, onBtnHex37bClick);
}
the if will check if btn_hex_37b is not null.
On the else method, you can give a timeouted method(but that is ugly), or give the eventlistener right after the creation of the object.
Hope this helped.
For Flash CS6, copy this swc:
/Applications/Adobe Flash CS6/Common/Configuration/ActionScript 3.0/libs/flash.swc
Into my Flash Builder project using these steps:
http://interactivesection.files.wordpress.com/2009/06/include_fl_packages_in_flex_builder-1.jpg
and then use this link
http://curtismorley.com/2013/03/05/app-used-to-work-with-air-3-2-or-3-4-doesnt-work-with-air-3-5-or-3-6/#comment-241102

Resources