Why does my AudioUnit (AUv3) host lose XPC connection immediately after instantiation in iOS 14? - audiounit

I'm an author of an AudioUnit host for iOS written in Objective C.
In iOS 14, it began crashing on instantiation of any AU instrument, but the same AUs work in other hosts. If I put a break in the completion handler for instantiateWithComponentDescription, I immediately see an error as soon as I step out (but not continue), before anything else is called:
Error in destroying pipe Error Domain=NSCocoaErrorDomain Code=4099 "The connection on anonymousListener or serviceListener from pid 630 was invalidated from this process." UserInfo={NSDebugDescription=The connection on anonymousListener or serviceListener from pid 630 was invalidated from this process.}
Sometimes it's a 4097. The next call into the plugin crashes the host, of course. In the log, the only entry that catches my eye is this:
default 14:38:47.105386-0700  MPC Pro 2    [u 01E943B9-94B5-4BF2-8926-9E843EB6482D:m (null)] [<private>(<private>)] invalidating startup assertion 
default 14:38:47.106987-0700  runningboardd  Invalidating assertion 32-637-996 (target:[xpcservice<com.retronyms.digits.Phase84-Component([application<com.akai.impcpro2>:637])>:639]) from originator [application<com.akai.impcpro2>:637]
default 14:38:47.733485-0700  SpringBoard   Workspace connection invalidated for <FBExtensionProcess: 0x156e2da50; xpcservice<com.retronyms.digits.Phase84-Component([application<com.akai.impcpro2>:637])>:639(v6BE)>
default 14:38:47.733583-0700  SpringBoard   [xpcservice<com.retronyms.digits.Phase84-Component([application<com.akai.impcpro2>:637])>:639] Now flagged as pending exit for reason: workspace client connection invalidated
Could there be some sort of access I need to give the app? How could I get more debug information out of this?

In case ARC has been disabled, make sure to force the AU to retain after completion:
[AUAudioUnit instantiateWithComponentDescription:descr options:{}
completionHandler:^(AUAudioUnit * nullable an_audio_unit, NSError * nullable
error) {
[an_audio_unit retain];
}];
Best

Related

Widevine Session Update endless Loop

I am using libwidevinecdm.so from chrome to handle DRM protected data. I am currently successfully setting the widevine server certificate I get from the license server. I can also create a session with the pssh box of the media im trying to decode. So far everything is successful (all promises resolve fine).
(session is created like this: _cdm->CreateSessionAndGenerateRequest(promise_id, cdm::SessionType::kTemporary, cdm::InitDataType::kCenc, pssh_box.data(), static_cast<uint32_t>(pssh_box.size()));)
I am then getting a session message of type kLicenseRequest which I am forwarding to the respective license server. The license server responds with a valid response and the same amount of data as I can see in the browser when using Chrome. I am then passing this to my session like this:
_cdm->UpdateSession(promise_id, session_id.data(), static_cast<uint32_t>(session_id.size()),
license_response.data(), static_cast<uint32_t>(license_response.size()));
The problem now is that this promise never resolves. It keeps posting the kLicenseRequest message over and over again to my session without ever returning. Does this mean my response is wrong? Or is this something else?
Br
Yanick
The issue is caused by the fact, that everything in CreateSessionAndGenerateRequest is done synchronous - that means by the time CreateSessionAndGenerateRequest returns your promise will always be resolved.
The CDM will emit the kLicenseRequest inside CreateSessionAndGenerateRequest and it doesn't do so in a "fire & forget" fashion, but the function waits there until you have returned from the cdm::Host_10::OnSessionMessage. Since my implementation of OnSessionMessage was creating a synchronous HTTP Request to the license server before - also synchronously - calling the UpdateSession the entire chain ended up to be blocking.
So ultimately I was calling UpdateSession while still being inside CreateSessionAndGenerateRequest and I assume the CDM cannot handle this and reacts by creating a new session with the given ID and generating a request again, which of course triggered another UpdateSession and so on.
Ultimately the simplest way to break the cycle was to make something asynchronous. I decided to launch a separate thread when receiving kLicenseRequest, wait for a few milliseconds to make sure that CreateSessionAndGenerateRequest has time to finish (not sure if that is really required) and then issue the request to the license server.
The only change I had to do was adding the surrounding std::thread:
void WidevineSession::forward_license_request(const std::vector<uint8_t> &data) {
std::thread{
[=]() {
std::this_thread::sleep_for(std::chrono::milliseconds{100});
net::HttpRequest request{"POST", _license_server_url};
request.add_header("Authorization", fmt::format("Bearer {}", _access_token))
.byte_body(data);
const auto response = _client.execute(request);
if (response.status_code() != 200) {
log->error("Widevine license request not accepted by license server: {} {} ({})", response.status_code(), response.status_text(), utils::bytes_to_utf8(response.body()));
throw std::runtime_error{"Error requesting widevine license"};
}
log->info("Successfully requested widevine license from license server");
_adapter->update_session(this, _session_id, response.body());
}
}.detach();
}

Why two calls to HttpSendRequest on different connections (new InternetOpen and new InternetConnect) bring different results?

I'm using wininet to connect to a url that needs a client certificate. To test my "automatic error correction", I'm doing this connection without the client certificate and the behaviour is to call my SelectCertificate function.
Intentionally I do not pass all the parameter to this function wich, of course, raises an exception and my request is aborted. There are cleaning blocks to do all the necessary cleaning [InternetCloseHandle(HttpOpenRequestHandle), InternetCloseHandle(InternetConnectHandle) and InternetCloseHandle(InternetOpenHandle)].
The first request is returnig the correct exception, caused by the lack of a client certificate, but the second (new?) request is raising another exception "Secure Channel Support Error" (error 12157)
To clarify, see the following flow:
The first request
1.0 InternetOpen(...)
2.0 InternetConnect(...)
3.0 HttpOpenRequest(...)
4.0 HttpSendRequest(..)
4.1 Error (ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED)
4.2 SelectCertificate
4.2.1 Raise exception because I intentionally do not passed all parameters
5.0 InternetCloseHandle(HttpOpenRequestHandle)
6.0 InternetCloseHandle(InternetConnectHandle)
7.0 InternetCloseHandle(InternetOpenHandle);
The second (new?) request
1.0 InternetOpen(...)
2.0 InternetConnect(...)
3.0 HttpOpenRequest(...)
4.0 HttpSendRequest(..)
4.1 Error (ERROR_INTERNET_SECURITY_CHANNEL_ERROR)
4.2 I do not know how to handle this error, so...
4.3 Raise the original exception "Secure Channel Support Error"
5.0 InternetCloseHandle(HttpOpenRequestHandle)
6.0 InternetCloseHandle(InternetConnectHandle)
7.0 InternetCloseHandle(InternetOpenHandle)
All other requests from now are just like the second one.
My questions are:
As I'm closing all the handles and doing a "totally new connection", the results between the calls should not be the same?
If not, why?
And there are a way to do an all new connection? How?
Actually, i only get a totally new connection by closing the entire application :( and starting over
The problem was caused by some kind of SSL cache, wich can be erased by executing the following code block BEFORE the request:
type
TSslEmptyCache = function (pszTargetName: LPSTR; dwFlags: DWORD): BOOL; WINAPI;
TIncrementUrlCacheHeaderData = function (nIdx: DWORD; lpdwData: LPDWORD): BOOL; WINAPI;
var
SchannelDLLHandle, WinInetHandle: HMODULE;
SslEmptyCache: TSslEmptyCache;
IncrementUrlCacheHeaderData: TIncrementUrlCacheHeaderData;
SchannelDLLHandle := LoadLibrary('schannel.dll');
WinInetHandle := LoadLibrary('wininet.dll');
if (SchannelDLLHandle > 0) and (WinInetHandle > 0) then
try
SslEmptyCache := GetProcAddress(SchannelDLLHandle,'SslEmptyCacheW');
IncrementUrlCacheHeaderData := GetProcAddress(WinInetHandle,'IncrementUrlCacheHeaderData');
if Assigned(SslEmptyCache) and Assigned(IncrementUrlCacheHeaderData) then
begin
SslEmptyCache(nil,0);
IncrementUrlCacheHeaderData(14,#buffer);
end;
finally
FreeLibrary(SchannelDLLHandle);
FreeLibrary(WinInetHandle);
end;
For more information, read this article.

Alamofire error on reopening app

I have been working on an app that allows the downloading of large files. I am using Swift 3 and Alamofire,
The downloads work in the background, and on iOS 10.2.x this all worked perfectly fine.
But on updating to iOS 10.3.x when the device is switched to sleep, upon opening the app again the following errors are thrown:
[] nw_socket_get_input_frames recvmsg(fd 6, 1024 bytes): [57] Socket is not connected
[] nw_endpoint_handler_add_write_request [1.1 192.124.249.2:443 failed socket-flow (satisfied)] cannot accept write requests
[] tcp_connection_write_eof_block_invoke Write close callback received error: [22] Invalid argument
The download is continuing in the background, and upon completion will trigger the completion callbacks fine. But because of these errors, it seems the progress callback isn't being called unless I close the app and open it again and reload the table cell view on open.
I can't find much info about these kind of errors online, only information on hiding the errors from being printed to the console.
Can anyone help?
Thanks
I had the same problem trying to download a large file (800 mb aprox) using Alamofire. At first my implementation was calling validate() and then responseData(queue:completionHandler:).
When this error occurs, Alamofire was catching it as a Failure with alamofire.AFError.ResponseValidationFailureReason.dataFileNil (whith no resumeData) which suggest that the closure sent on the to parameter is nil, which wasn't my case.
So my solution was removing the validate() call and doing the validation manually by catching the status codes on a switch.
Now without the validate() call Alamofire was catching the same error as a Failure but with a 200 as status code and resumeData. When this occurs I just make the download again but this time sending the resumeData on the download call.
Since the resumeData was almost at 100% (because the error happens when Alamofire is trying to write the file, at the end of the download) the second download was very short.
So basically my code looked like this:
switch response.response?.statusCode {
// other cases
case 200:
if let resumeData = response.resumeData {
// failed
// retry the download using resumeData
} else {
// succeed finished download
}
// more cases
}
If you need more info/details let me know

Multipeer Connectivity Not Connecting Programmatically

I am creating an iOS/macOS app that uses remote control functionality via the Multipeer Connectivity Framework. Since the device to be remotely monitored and controlled will run over an extended period of time, it's not viable to use the automatic view controller methods since the monitoring device may be locked or go to sleep and then disconnect the connection. So I'm using the programatic approach so that when the monitoring devices lose connection, they will automatically pair up when they are unlocked/woken up and the app is started again. My connection works fine using the ViewController method but not the programatic delegate approach. The advertising, browsing and inviting works fine, but when the invitation is accepted on the remote side I get several errors and then a failed connection. What's weird is that several of the errors are GCKSession errors.
So why is it trying to use the GameCenter framework? And why is it failing after accepting the invitation? Could it just be a bug in the Xcode 8 / Swift 3 /iOS 10 / macOS Sierra Beta SDKs?
[ViceroyTrace] [ICE][ERROR] ICEStopConnectivityCheck() found no ICE check with call id (2008493930)
[GCKSession] Wrong connection data. Participant ID from remote connection data = 6FBBAE66, local participant ID = 3A4C626C
[MCSession] GCKSessionEstablishConnection failed (FFFFFFFF801A0020)
Peer Changing
Failed
[GCKSession] Not in connected state, so giving up for participant [77B72F6A] on channel [0]
Here is the code from my connection class
func startAdvertisingWithoutUI () {
if advertiserService == nil {
advertiserService = MCNearbyServiceAdvertiser (peer: LMConnectivity.peerID, discoveryInfo: nil, serviceType: "mlm-timers")
advertiserService?.delegate = self
session.delegate = self
}
advertiserService?.startAdvertisingPeer()
}
func browserForNearbyDevices () {
if browserService == nil {
browserService = MCNearbyServiceBrowser (peer: LMConnectivity.peerID, serviceType: "mlm-timers")
browserService?.delegate = self
session.delegate = self
}
browserService?.startBrowsingForPeers()
}
func sendInvitation(to peer: MCPeerID) {
browserService?.invitePeer(peer, to: session, withContext: nil, timeout: 60)
}
func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: (Bool, MCSession?) -> Void) {
let trustedNames = GetPreferences.trustedRemoteDevices
for name in trustedNames {
if name == peerID.displayName {
invitationHandler(true,session)
return
}
}
invitationHandler (false, session)
}
None has worked for me.
I've resolved only disabling encryption...
let session = MCSession(peer:myPeerId, securityIdentity: nil, encryptionPreference: MCEncryptionPreference.none)
When the peerID used to make the session and the peerID used to make the advertiser or browser do not match, I get this part of the error.
[GCKSession] Wrong connection data. Participant ID from remote connection data = 6FBBAE66, local participant ID = 3A4C626C
Once peerIDs match, that part of the error goes away.
There might still be some other connection problems though.
I found out what was wrong. The MCPeerID object that I was passing into the MCSession instances, I was vending it as a Computed Class Property instead of storing it as a Stored Property. So I changed it to a Stored Instance Property and everything started working! Thanks Tanya for pointing me in the direction of the MCPeerID object.
Old Code
// Class Properties
static var localPeer : MCPeerID { return MCPeerID(displayName: GetPreferences.deviceName!) }
New Code
// Instance Properties
let localPeer = MCPeerID (displayName: GetPreferences.deviceName!)
The problem for me was that I never set the delegate of MCSession. I got all the same error messages that the OP mentioned, which made me think the connection was broken, but really I just forgot to set the delegate. After setting the delegate, all the error messages still printed, but otherwise my delegate methods got called normally upon receiving a message!
I've inflicted this problem on myself twice. Hopefully this helps someone reading along!
I got to work with TViOS 10.0 beta with this ...
peerID = MCPeerID(displayName: UIDevice.current.name)
Although I am still seeing this error...
2016-09-08 10:13:43.016600 PeerCodeATV[208:51135] [ViceroyTrace] [ICE][ERROR] ICEStopConnectivityCheck() found no ICE check with call id (847172408)
2016-09-08 10:13:47.577645 PeerCodeATV[208:51155] [GCKSession] SSLHandshake returned with error [-9819].
Same problem for me with an app I've had on the itunes store for years.
The latest 10.1 beta update now seems to fix the bluetooth issue with my app without any change to my code.

How to display remote email message?

I have been using this code to display IMAP4 messages:
void DisplayMessageL( const TMsvId &aId )
{
// 1. construct the client MTM
TMsvEntry indexEntry;
TMsvId serviceId;
User::LeaveIfError( iMsvSession->GetEntry(aId, serviceId, indexEntry));
CBaseMtm* mtm = iClientReg->NewMtmL(indexEntry.iMtm);
CleanupStack::PushL(mtm);
// 2. construct the user interface MTM
CBaseMtmUi* uiMtm = iUiReg->NewMtmUiL(*mtm);
CleanupStack::PushL(uiMtm);
// 3. display the message
uiMtm->BaseMtm().SwitchCurrentEntryL(indexEntry.Id());
CMsvOperationWait* waiter=CMsvOperationWait::NewLC();
waiter->Start(); //we use synchronous waiter
CMsvOperation* op = uiMtm->OpenL(waiter->iStatus);
CleanupStack::PushL(op);
CActiveScheduler::Start();
// 4. cleanup for example even members
CleanupStack::PopAndDestroy(4); // op,waiter, mtm, uimtm
}
However, in case when user attempts to download a remote message (i.e. one of the emails previously not retrieved from the mail server), and then cancels the request, my code remains blocked, and it never receives information that the action was canceled.
My question is:
what is the workaround for the above, so the application is not stuck?
can anyone provide a working example for asynchronous call for opening remote messages which do not panic and crash the application?
Asynchronous calls for POP3, SMTP and local IMAP4 messages work perfectly, but remote IMAP4 messages create this issue.
I am testing these examples for S60 5th edition.
Thank you all in advance.
First of all, I would retry removing CMsvOperationWait and deal with the open request asynchronously - i.e. have an active object waiting for the CMsvOperation to complete.
CMsvOperationWait is nothing more than a convenience to make an asynch operation appear synchronous and my suspicion is that this is culprit - in the case of download->show message, there are two asynch operations chained.