Open SCO Audio Connection with IOBluetoothAddSCOAudioDevice - objective-c

I am trying to emulate a HandsFree device from Mac OS X.
I advertise correctly my SDP service as Handsfree
I can pair my Android phone to my computer which is seen as "HandsFree" device
I can send a couple of AT Commands (AT+BRST, CIND, CMER) to establish a service level connection
I then install an Audio Driver to route all incoming/outgoing sound to/from the device
Unfortunately, it seems that the SCO channel is never opened. My android phone still emits sound (i.e.: when pressing dial pad) on its own speaker.
When going in the sound preferences of Mac OS X, I can see my device as an input/output device but the sound level never change.
Here is my code :
(void)rfcommChannelData:(IOBluetoothRFCOMMChannel*)rfcommChannel data:(void *)dataPointer length:(size_t)dataLength
{
... STATE MACHINE GOES HERE and SEND AT COMMANDS ...
... AT CMER OK RECEIVED ...
ret = IOBluetoothAddSCOAudioDevice([[rfcommChannel getDevice] getDeviceRef], NULL);
if (ret != kIOReturnSuccess ){
IOBluetoothRemoveSCOAudioDevice([[rfcommChannel getDevice] getDeviceRef]);
NSLog(#"%#", #"Deleting previously audio device");
ret = IOBluetoothAddSCOAudioDevice([[rfcommChannel getDevice] getDeviceRef], NULL);
if (ret != kIOReturnSuccess) {
NSLog(#"%#", #"Can't install Audio Driver");
}
}
Any idea on why the Audio Driver is installed and reported by the system but can't open an SCO connection ?

Related

Domain=org.webrtc.RTCPeerConnection Code=-1 "Failed to set remote offer sdp: Failed to set remote video description send parameters."

I keep getting this error on my iOS webrtc app using the webrtc when I take the sdp and try to set it as remote description. I've tried adjusting the sdp cause I thought it wasn't able to parse the string but it didn't work.
peerConnection = prepareNewConnection();
peerConnection.setRemoteDescription(sdp) { (Error) in
if Error != nil{
print("sdp creation error: \(String(describing: Error!.localizedDescription))")
}
}

Arduino MKR1000 not able to connect to AWS API Gateway

I tried modifying the basic Arduino code from here in order to send HTTP Requests to AWS API Gateway. While the example code from the link worked, I was not able to get a successful connection with AWS API Gateway.
I have tried a combination of things such as removing the https:// from server[], changing the port to 443 instead of 80, removing the /beta from server[], using client.connectSSL instead of client.connect, but none of these have worked so far.
The line:
int err = client.connect(server, 80);
returns me a value of 0.
There are no certificates set up with the AWS API Gateway, so I don't think it's a problem with that. Wifi works perfectly.
Any help would be greatly appreciated!
#include <SPI.h>
#include <WiFi101.h>
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or
use as key for WEP)
int keyIndex = 0; // your network key Index number (needed only for WEP)
int status = WL_IDLE_STATUS;
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
char server[] = "https://**********.execute-api.us-west-2.amazonaws.com/beta"; // name address for Google (using DNS)
WiFiClient client;
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi shield not present");
// don't continue:
while (true);
}
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
Serial.println("Connected to wifi");
printWiFiStatus();
Serial.println("\nStarting connection to server...");
// if you get a connection, report back via serial:
int err = client.connect(server, 80);
Serial.println(err);
if (err) {
Serial.println("connected to server");
// Make a HTTP request:
client.println("GET /beta HTTP/1.1");
client.println("Host: https://**********.execute-api.us-west-2.amazonaws.com");
client.println("Connection: close");
client.println();
}
}
void loop() {
// if there are incoming bytes available
// from the server, read them and print them:
while (client.available()) {
char c = client.read();
Serial.write(c);
}
// if the server's disconnected, stop the client:
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting from server.");
client.stop();
// do nothing forevermore:
while (true);
}
}
void printWiFiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
Tips:
(1) client.connect(fqdn, port) is expecting an FQDN for the first parameter
The example in the docs is client.connect("Arduino.cc", 80) this seems to work well in my tests. The docs say "URL" but they mean FQDN.
(2) If you need SSL then you MUST load up your certs using the firmware updater
first. If you are using non-standard pins for the WiFi101 board then you MUST use wifi.setPins() to set the pins or the firmware updater will fail. Adafruit Feather M0 1500 owners will know what I am talking about here.
Reference: https://www.arduino.cc/en/Reference/WiFi101ClientConnect
I hope this helps.

IP address/ OS version and device key

I have MobileFirst (V7.O) Hybrid app . How can I get the current IP address, OS version (android nnn, Iphone nnn), Device unique Id for the device. Basically, I am recording some information at various point in my app.
Can you please provide some hints and how to get this information
Thanks for your help
You can be found deviceID & IP address below information
unique deviceID
WL.Device.getID({onSuccess : function(o) {
alert(o.deviceID);
}, onFailure : function(e) {
WL.Logger.info("Error getting ID: " + e);
}});
IP address
WL.Device.getNetworkInfo(function (networkInfo) {
alert (networkInfo.ipAddress);
});
Device OS version use cordova
var deviceVersion = device.version;
check cordova api https://cordova.apache.org/docs/en/3.0.0/cordova/device/device.html
more this link http://www-01.ibm.com/support/knowledgecenter/SSZH4A_6.2.0/com.ibm.worklight.apiref.doc/html/refjavascript-client/html/WL.Device.html?cp=SSZH4A_6.2.0%2F10-0-0-1-9

FTDI via libusb error EPIPE

I'm trying to work with an FTDI-based USB device and I'm getting a -32 (EPIPE) error:
08-06 16:32:16.328: WARN/System.err(15547): ftdi_usb_open_dev()
08-06 16:32:16.328: WARN/System.err(15547): usb_detach_kernel_driver_np()libusb: 0.029116 debug [libusb_detach_kernel_driver] interface 0
08-06 16:32:16.328: WARN/System.err(15547): ftdi claim interface ...
08-06 16:32:16.328: WARN/System.err(15547): libusb-compat debug: usb_claim_interface: interface 0
08-06 16:32:16.328: WARN/System.err(15547): libusb: 0.030246 debug [libusb_claim_interface] interface 0
08-06 16:32:16.328: WARN/System.err(15547): claiming interface using fd = 4
08-06 16:32:16.328: WARN/System.err(15547): ftdi_usb_reset ...
08-06 16:32:16.328: WARN/System.err(15547): libusb-compat debug: usb_control_msg: RQT=40 RQ=0 V=0 I=0 len=0 timeout=300
08-06 16:32:16.328: WARN/System.err(15547): libusb: 0.031222 debug [libusb_get_next_timeout] next timeout in 0.300000s
08-06 16:32:16.328: WARN/System.err(15547): libusb: 0.031527 debug [libusb_handle_events_timeout_completed] doing our own event handling
08-06 16:32:16.328: WARN/System.err(15547): libusb: 0.032046 debug [handle_events] poll() 2 fds with timeout in 300ms
08-06 16:32:16.328: WARN/System.err(15547): libusb: 0.033023 debug [handle_events] poll() returned 1
08-06 16:32:16.338: WARN/System.err(15547): libusb: 0.033389 debug [reap_for_handle] urb type=2 status=-32 transferred=0
08-06 16:32:16.338: WARN/System.err(15547): libusb: 0.033755 debug [handle_control_completion] handling completion status -32
08-06 16:32:16.338: WARN/System.err(15547): libusb: 0.034091 debug [handle_control_completion] unsupported control request
08-06 16:32:16.338: WARN/System.err(15547): libusb: 0.034366 debug [usbi_handle_transfer_completion] transfer 0x2915e0 has callback 0x5ccb4
08-06 16:32:16.338: WARN/System.err(15547): libusb: 0.034732 debug [ctrl_transfer_cb] actual_length=0
The USB request seems to be exactly as it is required according to FTDI Chip Commands.
FTDI context is initialized without errors, usb_dev is not null and it seems to be okay. The cable is okay as I can use it for uploading Arduino sketches to Duemilanove (FTDI) boards.
So I'm completely stuck.. What should I do?
My code
struct ftdi_context *ftdi_ctx;
struct usb_device *dev;
usb_dev_handle *udev;
// ...
ftdi_ctx = ftdi_new();
if (ftdi_ctx == NULL) {
fprintf(stderr, "error init ftdi context\n");
return 1;
}
ftdi_ctx->usb_write_timeout = 0;
ftdi_ctx->usb_read_timeout = 0;
// ...
udev = usb_open(dev);
int ret = ftdi_usb_open_dev(ftdi_ctx, dev, udev);
if (ret < 0) {
fprintf(stderr, "error opening ftdi device\n");
return ret;
}
ftdi_usb_open_dev() is slightly modified to get ready usb_device and don't do usb_open inside:
libftdi-0.1 code (ftdi.c):
int ftdi_usb_open_dev(struct ftdi_context *ftdi, struct usb_device *dev, struct usb_dev_handle *usb_dev)
{
int detach_errno = 0;
int config_val = 1;
fprintf(stderr, "ftdi_usb_open_dev()\n");
if (ftdi == NULL) {
fprintf(stderr, "ftdi context invalid\n");
ftdi_error_return(-8, "ftdi context invalid");
}
// 4ntoine (no need to open device if usb_dev is already passed)
if (usb_dev == NULL) {
if (!(ftdi->usb_dev = usb_open(dev)))
ftdi_error_return(-4, "usb_open() failed");
} else {
ftdi->usb_dev = usb_dev;
}
#ifdef LIBUSB_HAS_GET_DRIVER_NP
// Try to detach ftdi_sio kernel module.
// Returns ENODATA if driver is not loaded.
//
// The return code is kept in a separate variable and only parsed
// if usb_set_configuration() or usb_claim_interface() fails as the
// detach operation might be denied and everything still works fine.
// Likely scenario is a static ftdi_sio kernel module.
fprintf(stderr, "detaching kernel driver... \n");
if (ftdi->module_detach_mode == AUTO_DETACH_SIO_MODULE)
{
fprintf(stderr, "usb_detach_kernel_driver_np() ...\n");
if (usb_detach_kernel_driver_np(ftdi->usb_dev, ftdi->interface) != 0 && errno != ENODATA) {
fprintf(stderr, "failed to detach\n");
detach_errno = errno;
}
}
#endif
fprintf(stderr, "ftdi claim interface ...\n");
if (usb_claim_interface(ftdi->usb_dev, ftdi->interface) != 0)
{
fprintf(stderr, "failed to claim interface\n");
ftdi_usb_close_internal (ftdi);
if (detach_errno == EPERM)
{
ftdi_error_return(-8, "inappropriate permissions on device!");
}
else
{
ftdi_error_return(-5, "unable to claim usb device. Make sure the default FTDI driver is not in use");
}
}
fprintf(stderr, "ftdi claimed interface\n");
fprintf(stderr, "ftdi_usb_reset ...\n");
if (ftdi_usb_reset (ftdi) != 0)
{
ftdi_usb_close_internal (ftdi);
ftdi_error_return(-6, "ftdi_usb_reset failed");
}
I've tested it with another FTDI-board (Arduino Nano v3) and still the same error, so the problem is not in the board most likely...
I've tested it on another Android device with USB host support too and another Android OS version (4.0.x) and still the same error...
Is your host system Windows or Linux?
It seems that the device failed to respond to the control message issued by ftdi_usb_reset(). And the ftdi_usb_reset() is actually called by ftdi_usb_open_dev().
If checking the libftdi source code:
http://www.intra2net.com/en/developer/libftdi/documentation/ftdi_8c_source.html#l00522
We found that it shall return -6 if ftdi_usb_reset() fails. The entire error log is not posted here, so I wonder if it is what truly happened finally. And maybe there are more interesting things to go see there.
Maybe showing your code here can help get a better understanding. :)
If possible on your side, when trying to do the same thing with D2XX driver provided by ftdichip.com, will the result be the same?
Correct me if my understanding is wrong: You are developing native code that works on Android (the underlying Linux system) that calls libftdi and libusb, right? And I assume the purpose is to use Android devices through libusb without root needed?
A little search on Google tells me that there is no "official" Android port for libusb. Some platform works with libusb while some cannot. People are having different kinds of feedbacks.
So if going back to basics, say, using only the functions in libusb, without the libftdi code you've modified, can you perform device open, close, and send control message to your FTDI device through basic libusb functions?
Or, if possible, try with an unmodified libftdi. Will it to the job it is supposed to do?
And by the way, why libftdi0.1? I knew it should be version 1.0 by now. Older versions could be buggy...
I just try to provide something that is worth trying. It could be a libusb problem, a libftdi problem, or simply a problem of the sequence how you operate the device. So if not sure where it goes wrong, then break them down to pieces and identify what are correct would be what I would try.

How to check for version of app and request users to update?

How can I check if the user has the current version of my app and also pop up a message to request them to update their app version?
Something like what you would see below.
You need to have a WebService on your server (or something similar) that your app requests at startup, to know which is the latest version available. (If you don't have a WS yet and really don't want to implement one for that, you may also simply use an XML or text file that contains the version too)
Then compare this version retrieved from your server with the current version of the application, using [[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleVersion"].
If they are different, you can display the alertview and redirect to itms-apps://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftwareUpdate?id=[APPID]&mt=8 (replacing APPID with your iTunes Connect App ID), which is the link that will make your iPhone open the AppStore application directly on your application's update page
To check to see if you have the latest version just query iTunes for app data using the following query (note: change the id to match your app's id from iTunesConnect):
http://itunes.apple.com/lookup?id=520604518
This returns a JSON dictionary which is very easy to convert to an NSDictionary to use directly within your code, then all you need to do is pull out the value for the "version" key and compare it against your apps version number (see version key/value bolded below):
{
"resultCount": 1,
"results": [
{
"kind": "software",
"features": [],
"supportedDevices": [
"all"
],
"isGameCenterEnabled": false,
"artistViewUrl": "https://itunes.apple.com/us/artist/d-m-holdings/id388608883?uo=4",
"artworkUrl60": "http://a899.phobos.apple.com/us/r1000/086/Purple/v4/6d/b3/05/6db305aa-c685-558b-8c8e-8b7245375ce1/IconAudio.png",
"screenshotUrls": [
"http://a86.phobos.apple.com/us/r1000/078/Purple/v4/8f/ff/47/8fff4783-f2e4-fe3f-ef92-96d67d66c12b/mzl.dwbdvxny.png",
"http://a731.phobos.apple.com/us/r1000/097/Purple/v4/cb/65/f6/cb65f613-408a-dffe-fb36-165db0c1a360/mzl.jexyhdnq.png",
"http://a940.phobos.apple.com/us/r1000/097/Purple/v4/f6/26/a1/f626a18c-691f-7345-8d3d-f19713144818/mzl.llsgsagl.png",
"http://a185.phobos.apple.com/us/r1000/071/Purple/v4/7d/5e/bc/7d5ebcad-7755-e772-727c-65de99effd60/mzl.zuyvhebk.png",
"http://a48.phobos.apple.com/us/r1000/096/Purple/v4/d6/f5/f1/d6f5f108-10ab-3738-26cf-5ce82c6bb690/mzl.ijtyynie.png"
],
"ipadScreenshotUrls": [],
"artworkUrl512": "http://a672.phobos.apple.com/us/r1000/100/Purple/v4/e3/cb/5d/e3cb5d2d-f1a8-8b80-3a91-58be8f654710/mzm.uogqezwx.png",
"artistId": 388608883,
"artistName": "D&M Holdings",
"price": 0,
**"version": "1.0.5",**
"description": "Designed to enhance the listening experience with Denon’s new line of Music Maniac™ headphones, the Denon Audio app is designed for the on-the-go audiophile. The Denon Audio app features a premium audio player that lets you experience the best possible sound quality from your iPod music library and favorite Internet radio stations. Create & save custom EQ curves, create & save instant playlists, enjoy internet radio stations via the built-in TuneIn service, and more. The Denon Audio app will quickly replace all of your other music apps.\n \nThe Denon Audio app features a customizable graphical equalizer that lets you contour your own sound by directly manipulating more than 1000 discrete bands of equalization without adding spatial distortion or decreasing sound quality. Pump up the bass, restore those highs, and start jammin’! \n \nEQ FEATURES:\n \n• Graphical equalizer for your iPod music library and streaming Internet Radio\n• 1000 possible discrete bands\n• 10 built in EQ Presets\n• Create and save your own EQ Presets\n• Bypass mode to quickly compare the original and equalized audio\n• Real-time spectrum analyzer\n• Linear phase design\n• No spatial distortion\n\nIPOD MUSIC LIBRARY FEATURES:\n\n• Enhances your listening experience with Denon Music Maniac Headphones or other audio playback devices such as docking stations, a/v receivers, car stereos via USB, Bluetooth, or Airplay.\n• Powerful queue based playback system lets you build and order your own playlist on the fly.\n• Save the playback queue as a new playlist\n• A single song, all songs on an album, all songs by an artist, and all songs in a genre can easily be added to the now playing queue.\n• Supports both portrait and landscape modes for browsing, playing, and equalizing\n• Shuffle and repeat playback modes\n• iPod library browsing by Playlist, Artist, Album, Song, Genre, Composer, Compilation, and Podcast (no importing needed)\n\nINTERNET RADIO FEATURES:\n\n• The TuneIn service provides global access to Internet radio – covering over 70,000 radio stations and 2 million on-demand programs including sports, news, talk, music and comedy. \n• Browse Internet radio stations by location, genre, language or Podcast (on-demand programs).\n• Powerful search feature for your iPod music library and Internet Radio \n• Save your favorite Internet Radio stations or programs as convenient presets and share them with other TuneIn compatible devices\n• Ability to choose high or low quality streams offered by broadcasters\n \nADDITIONAL FEATURES:\n\n• Streams music over AirPlay to any Denon AirPlay compatible receiver or HiFi product\n• Share what you’re listening to via Facebook, Twitter, Email, or Text Message (iMessage)\n\nNOTICES:\n \n• The Denon Audio app requires iOS 5 or later and works with the iPhone 3GS or newer, the iTouch 3rd generation or newer, and all iPads (in 2x mode). \n• DRM protected iTunes music is NOT supported by the Denon Audio app (or any 3rd party music app)\n• iTunes Match will be supported in a future update \n• WiFi or data connection required to stream Internet radio",
"currency": "USD",
"genres": [
"Music",
"Lifestyle"
],
"genreIds": [
"6011",
"6012"
],
"releaseDate": "2012-05-29T07:00:00Z",
"sellerName": "D&M Holdings Inc.",
"bundleId": "com.dm-holdings.denon-audio",
"trackId": 520604518,
"trackName": "Denon Audio",
"primaryGenreName": "Music",
"primaryGenreId": 6011,
"releaseNotes": "• Added 4\" display support for the iPhone 5 and 5th generation iPod Touch\n\n• Added an audio limiter function to protect against possible distortion introduced from pushing the EQ too high\n\n• Displays the Shuffle, Repeat, AirPlay, and Share icons as well as the scan/scrub controls on the \"Now Playing\" screen by default (so everyone knows they are included in the app). Tap the cover art to hide/show these controls",
"formattedPrice": "Free",
"wrapperType": "software",
"trackCensoredName": "Denon Audio",
"trackViewUrl": "https://itunes.apple.com/us/app/denon-audio/id520604518?mt=8&uo=4",
"contentAdvisoryRating": "4+",
"artworkUrl100": "http://a672.phobos.apple.com/us/r1000/100/Purple/v4/e3/cb/5d/e3cb5d2d-f1a8-8b80-3a91-58be8f654710/mzm.uogqezwx.png",
"languageCodesISO2A": [
"ZH",
"DE",
"EN",
"ES",
"FR",
"JA",
"NL"
],
"fileSizeBytes": "9060882",
"sellerUrl": "http://www.usa.denon.com/headphones",
"averageUserRatingForCurrentVersion": 4.5,
"userRatingCountForCurrentVersion": 329,
"trackContentRating": "4+",
"averageUserRating": 4.5,
"userRatingCount": 471
}
]
}
Here is some code to accomplish this task. -rrh
NSURL *url = [[NSURL alloc] initWithString:[NSString stringWithFormat:#"http://itunes.apple.com/lookup?id=%#",APPSTORE_ID]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (!error) {
NSError* parseError;
NSDictionary *appMetadataDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&parseError];
NSArray *resultsArray = (appMetadataDictionary)?[appMetadataDictionary objectForKey:#"results"]:nil;
NSDictionary *resultsDic = [resultsArray firstObject];
if (resultsDic) {
// compare version with your apps local version
NSString *iTunesVersion = [resultsDic objectForKey:#"version"];
NSString *appVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)#"CFBundleShortVersionString"];
if (iTunesVersion && [appVersion compare:iTunesVersion] != NSOrderedSame) { // new version exists
// inform user new version exists, give option that links to the app store to update your app - see AliSoftware's answer for the app update link
UIAlertView *alert = [UIAlertView bk_showAlertViewWithTitle:APP_NAME message:[NSString stringWithFormat:#"New version %# available. Update required.",iTunesVersion] cancelButtonTitle:#"update" otherButtonTitles:nil handler:^(UIAlertView *alertView, NSInteger buttonIndex) {
NSString *iTunesLink = [NSString stringWithFormat:#"itms://itunes.apple.com/us/app/apple-store/id%#?mt=8",APPSTORE_ID];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:iTunesLink]];
}];
[alert show];
}
}
} else {
// error occurred with http(s) request
NSLog(#"error occurred communicating with iTunes");
}
}];