Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS sound support #1875

Merged
merged 16 commits into from
Sep 9, 2021
Merged

iOS sound support #1875

merged 16 commits into from
Sep 9, 2021

Conversation

ngocdh
Copy link
Contributor

@ngocdh ngocdh commented Jun 14, 2021

Short description of changes

What's included in this PR:

  • iOS sound support
  • a feature for iOS to switch between external device (when plugged in) and the internal mic
  • A crash fix related to the way iOS handles sockets in idle mode

Context: Fixes an issue?

As discussed in #1865, here is the new iOS-only PR.

Does this change need documentation? What needs to be documented and how?
Yes. Compilation for iOS is already documented.

Status of this Pull Request

Waiting on review; iOS sound is working. Some more real world tests.

What is missing until this pull request can be merged?

Real world tests; review;

Later on: decide if we do a squash and merge.

Checklist

  • I've verified that this Pull Request follows the general code principles
  • I tested my code and it does what I want
  • My code follows the style guide
  • I waited some time after this Pull Request was opened and all GitHub checks completed without errors.
  • I've filled all the content above

PR-Template applied by @ann0see

@ngocdh ngocdh mentioned this pull request Jun 14, 2021
ios/sound.h Outdated Show resolved Hide resolved
ios/sound.h Show resolved Hide resolved

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See, it's lines like this where I feel clang-format hasn't done its job right.

- ( BOOL ) application: ( UIApplication* ) application didFinishLaunchingWithOptions: ( NSDictionary* ) launchOptions

but I don't know Objective-C...

Copy link
Contributor

@emlynmac emlynmac Jun 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too many spaces for Obj-C (referring to other review comment with lots of spaces)

Most places I have worked like a space between the type and the *
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that "too many" as in "won't compile" or as in "not normal"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh it's just purely a stylistic comment - there are religious discussions about how to format Obj-C....
It makes no difference to compilation.

ios/sound.mm Outdated Show resolved Hide resolved
@ann0see
Copy link
Member

ann0see commented Jun 14, 2021

@ngocdh to keep the commit history clean, you should use amend style changes to the last commit and then git push --force the new commit to your branch ;-).

ios/sound.mm Outdated Show resolved Hide resolved
ios/sound.mm Outdated
[[AVAudioSession sharedInstance] requestRecordPermission:^( BOOL granted ) {
if ( granted )
{
// ok
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if it isn't..?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should probably show an error message. (Which also doesn't happen on macOS #1576)

ios/sound.mm Outdated
{
// regular case: no mixing input channels used
lNumInChanPlusAddChan = lNumInChan;
qDebug ( "Sound exception ...." );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally I've seen this style in the code:

qDebug() << "Sound exception";

Is there a reason to do it differently?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just 2 ways to do the same thing. Although your way requires #include

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's why we've code style guidelines that say "do it like it's done elsewhere" rather than "do whatever you like".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually have a valid reason to limit the libraries included. Initially, the iOS code had a few more unnecessary #includes, and @ann0see iPhone couldn't even launch Jamulus because it took too long. Launched after removing libs, so I prefer to stay away from #include when possible.

The qDebug() << syntax requires #include <QDebug>.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#include changes don't change the launch time.

If the function call requires the library to work then I don't see how you can avoid it.

As far as start up performance goes, you have to not block the main thread for long periods or you'll be killed by the system. It's pretty established that this is the ::init call happening too many times.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#include changes don't change the launch time.

It seemed to do though. We did a test with @ann0see iphone which at first couldn't launch because it took too long. Removed some unused libs, and it launched.

If the function call requires the library to work then I don't see how you can avoid it.

The thing here is qDebug("something") can be called without #include QDebug, while qDebug() << "something" can't. Although I'm sure QDebug is already included in other ios-unrelated parts of the code, I'm just trying to optimize because ios launch time is yet to be improved.

As far as start up performance goes, you have to not block the main thread for long periods or you'll be killed by the system. It's pretty established that this is the ::init call happening too many times.

Yeah I proposed multithreading...

I actually see another potential issue: MAX_NUM_CHANNELS (default value=150). If I'm not mistaken, at launch, Jamulus creates MAX_NUM_CHANNELS faders in the mixer, and hide unused ones.

However, seeing that other OSes don't seem to have problem with this, the problem might be CSound::Init, which is specific to each system.

ios/sound.mm Outdated Show resolved Hide resolved
ios/sound.mm Outdated Show resolved Hide resolved
ios/sound.mm Show resolved Hide resolved
ios/sound.mm Show resolved Hide resolved
ios/sound.mm Outdated
}
catch ( const CGenErr& generr )
{
qDebug ( "Sound Init exception ...." );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And again regarding qDebug() << "message";

ios/sound.mm Outdated
}
catch ( const CGenErr& generr )
{
qDebug ( "Sound Start exception ...." );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here.

ios/sound.mm Outdated
}
catch ( const CGenErr& generr )
{
qDebug ( "Sound Stop exception ...." );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...

src/main.cpp Show resolved Hide resolved
src/socket.cpp Outdated Show resolved Hide resolved
src/socket.cpp Outdated Show resolved Hide resolved
src/socket.cpp Outdated Show resolved Hide resolved
src/socket.h Outdated Show resolved Hide resolved
@ngocdh
Copy link
Contributor Author

ngocdh commented Jun 14, 2021

@ngocdh to keep the commit history clean, you should use amend style changes to the last commit and then git push --force the new commit to your branch ;-).

I actually have no idea what you're talking about because of my very limited experience, but thanks I'll keep that in mind.

@ann0see
Copy link
Member

ann0see commented Jun 14, 2021

No problem ;-).

Let’s say you did a commit and changed a typo. After committing and pushing, you realise that there’s another typo. Ok, let’s do another commit. Oh no. Now I accidentally deleted a closing bracket —> next commit. Argh, no there’s another typo —> commit etc. As you see, you now have lots of unneeded commits.

What if you could modify these commits and just fix typos in one commit?

That’s the place where you could use git commit --amend/ git rebase,… https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History

And then git push --force the new commit history and be happy about a clean and understandable history.

Last year I also committed a bunch of unneeded commits to my repo and it was part of a PR (#807). It got merged as is into master and now there’s a lot of garbage in there.

@ngocdh
Copy link
Contributor Author

ngocdh commented Jun 14, 2021

Ok so I went thru the very thorough reviews from @pljones. Now my code is much better, but I'm refraining from sending a commit to keep history clean because there's still the clang-format to sort out.

I say let's just let those style issues slide for now. When we have a better .clang-format, it's just one command away to correct the ObjC style for the whole project.

What does the team think?

@ann0see
Copy link
Member

ann0see commented Jun 14, 2021

You could amend 6ac16f6 And later (after we have a working .clang_format we‘d apply it to all mm files.

@ann0see ann0see changed the title iOS sound support 3 iOS sound support Jun 14, 2021
@pljones
Copy link
Collaborator

pljones commented Jun 14, 2021

Yep, we'll have to comply with the exist clang-format checks on this PR.

ios/sound.mm Outdated
//CSoundBase::Start();
}
// release the malloc'ed data in the buffer we created earlier
free ( bufferList.mBuffers[0].mData );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be no (absolute) allocation and freeing of memory inside the audio processing loop. It's a major source of performance hits. Admittedly, I'm not familiar with how it's done for other platforms but if possible, allocate the buffer once when the app starts, then re-use it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might be right. I was following this example: https://github.com/Epskampie/ios-coreaudio-example/blob/master/IosAudioController.m which really helped me.
About performance, I've been playing with my iPhone to listen to people and jam for hours and didn't really have any problem.
I'll keep that in mind and see if I can do anything to make it better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to use a pointer to store the buffer address, so that the buffer only needs to be initialized once and can be reused. However, since recordingCallback is a static function, the pointer must also be static. When compiling in xCode, I had this linker error (couldn't access that pointer from CSound or something).

Do you know how to overcome this error?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest making recordingCallback not static, as a member of a single-instance class it should still be unique - so make sure the class it belongs to is single-instance. Then the buffer pointer should be a member of the same single-instance class, pointing to memory allocated when that class is instantiated.

I don't know iOS or ObjectiveC, though, to know how best to make that happen.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried, but it seems the callback has to be static :(

Copy link
Contributor Author

@ngocdh ngocdh Jun 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ha ha got it working! The secret is the pointer has to be called like this: pSound->pointer, not just pointer. Now 1 malloc only in constructor, which is freed in destructor. It seems to work, but I'm testing a bit more before committing.

Copy link
Contributor Author

@ngocdh ngocdh Jun 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I checked the MacOS sound code, and there're mallocs there ...

@@ -241,57 +266,73 @@ void CSocket::SendPacket ( const CVector<uint8_t>& vecbySendBuf, const CHostAddr
// char vector in "const char*", for this we first convert the const
// uint8_t vector in a read/write uint8_t vector and then do the cast to
// const char *)
if ( HostAddr.InetAddr.protocol() == QAbstractSocket::IPv4Protocol )

for ( int tries = 0; tries < 2; tries++ ) // retry loop in case send fails on iOS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't an ifdef for iOS be better here (if it's only needed on iOS)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's @softins code. I don't think iOS needs it though, but it might be a good idea to leave the loop there for all OSes, just as a safety mesure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the whole point of using UDP was that it was lossy. How did a retry mechanism end up being needed here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emlynmac in iOS when you lock the device, all inactive sockets are closed. When device is unlocked, and user tries to connect to a server for example, the app crashes because of the closed socket.
As far as I understand, the status check in the loop only concerns the socket (because it can not know if packet reached its destination), if socket is closed, then status < 0, that's when we need to reinit the socket and send the packet again.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emlynmac Application level reliability is common for ensuring a message gets through. However, for audio/video stream, retry/retransmission is not used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emlynmac Application level reliability is common for ensuring a message gets through. However, for audio/video stream, retry/retransmission is not used.

This is handled elsewhere for messages that need it.

@ngocdh Thanks - I see.

@pljones
Copy link
Collaborator

pljones commented Sep 6, 2021

There's a few comments I made that it looked like were intended to have been fixed -- but they don't appear to have been. I'm not sure if in the rebasing some commit got lost or what.

@ann0see
Copy link
Member

ann0see commented Sep 6, 2021

Hmm. Maybe. But the comments should still be there.

@ngocdh
Copy link
Contributor Author

ngocdh commented Sep 6, 2021

I haven't done anything about your last batch of comments @pljones, was waiting for more :) I'm on it.
@softins thank you for the rebase.
@ann0see you can change device in Settings, just like in other OSes.

@ann0see
Copy link
Member

ann0see commented Sep 6, 2021

Thanks. Just saw it.

@ngocdh
Copy link
Contributor Author

ngocdh commented Sep 6, 2021

Please could someone try compiling it for iOS and running?

My Mac is having trouble synchronizing with test devices. I sadly can't do anything right now.

@ngocdh
Copy link
Contributor Author

ngocdh commented Sep 6, 2021

Ok, so I checked @pljones comments and made two (really) minor changes accordingly: a typo (steoreo -> stereo) and and a break in a loop. The third comment couldn't be taken into account because iOS works with float, not integer, so conversion is required.

Now if you're all ok with the above, I will send my last commit (hopefully) for this PR.

@ann0see
Copy link
Member

ann0see commented Sep 7, 2021

I‘d be ok with that

@ann0see
Copy link
Member

ann0see commented Sep 7, 2021

@softins thanks.

Before merging, I‘d like to have an approval by @pljones too.

@ann0see ann0see requested a review from pljones September 7, 2021 15:28
@ann0see
Copy link
Member

ann0see commented Sep 7, 2021

@pljones or @ngocdh could you please open an issue on the outstanding tasks?

@ngocdh
Copy link
Contributor Author

ngocdh commented Sep 7, 2021

@pljones or @ngocdh could you please open an issue on the outstanding tasks?

My outstanding issue is already described in #1727 #1727

@pljones
Copy link
Collaborator

pljones commented Sep 8, 2021

I don't think I can review the code here. It's not following the way the rest of Jamulus works, it's Apple-specific. So it needs someone who knows the platform to review it.

@pljones pljones removed their request for review September 8, 2021 06:18
@ann0see ann0see requested review from pljones and ann0see and removed request for pljones September 8, 2021 06:54
Copy link
Member

@ann0see ann0see left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@emlynmac can you Review and approve this?

@emlynmac
Copy link
Contributor

emlynmac commented Sep 8, 2021

@emlynmac can you Review and approve this?

I don't have any means to test this code; the fact that QT is so old coupled with the version of Xcode required means you cannot build on Big Sur.
I don't have any issues with the code, but not being able to test it means I can't really verify it either.

@pljones
Copy link
Collaborator

pljones commented Sep 8, 2021

OK, can we mark the build on Apple Store as experimental? Or does that break Apple Store distribution?

@emlynmac
Copy link
Contributor

emlynmac commented Sep 8, 2021

OK, can we mark the build on Apple Store as experimental? Or does that break Apple Store distribution?

There will be no apple store distribution - #1874 needs resolving.
You may not publish a beta to the App Store also. Testflight is the means for distribution beta versions.
Oh and of course, we can't publish unless I can build it, so that's a no-go until we push up to more recent versions of QT / Xcode that work on Big Sur.

@ngocdh
Copy link
Contributor Author

ngocdh commented Sep 8, 2021

so that's a no-go until we push up to more recent versions of QT / Xcode that work on Big Sur.

I'm confused: you can't build because you must maintain the same environment as Jamulus autobuild?

@emlynmac
Copy link
Contributor

emlynmac commented Sep 8, 2021

so that's a no-go until we push up to more recent versions of QT / Xcode that work on Big Sur.

I'm confused: you can't build because you must maintain the same environment as Jamulus autobuild?

Well, it should always be the same environment as the official build yes. But, additionally, the QT5 build environment is not functional with big sur. I used to have an old laptop with Catalina on it, but that is no more...

@ann0see
Copy link
Member

ann0see commented Sep 9, 2021

Hmm. I‘d say since building for IOS worked and the CI is green, this should be OK to merge.

@gilgongo gilgongo added this to the Release 3.8.1 milestone Sep 9, 2021
@softins softins merged commit b5511b8 into jamulussoftware:master Sep 9, 2021
Bryanpenaaa

This comment was marked as spam.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants