ryanheise / audio_service

Flutter plugin to play audio in the background while the screen is off.
803 stars 480 forks source link

iOS Support #10

Closed hacker1024 closed 4 years ago

hacker1024 commented 5 years ago

I'm creating this issue to keep track of an iOS implementation. I myself am an Android developer, and I'd love to see an iOS developer contribute.

ryanheise commented 4 years ago

@alexandergottlieb your pull request didn't compile for me, but I've fixed the errors, and also commented out one line which was causing a runtime error. I'm not sure why, but this line:

[commandCenter.changePlaybackPositionCommand addTarget:self action:@selector(changePlaybackPosition)]

caused this error:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSInvocation _invocationWithMethodSignature:frame:]: method signature argument cannot be nil'

(edit: I've now fixed the bug)

That said, I'm sadly unable to test much of this on the simulator. Does anyone know how I can access the control center on the iPhone simulator?

DGempler commented 4 years ago

@ryanheise support for the control center got dropped with the ios 11 simulator. I was able to work on & test @alexelisenko 's audio_player_service by downloading ios 10 and running the simulator with that version.

ryanheise commented 4 years ago

Thanks, @DGempler !

I have just committed some code to update the nowPlayingInfo.

I should also say, this code doesn't actually work ;-) But, it's progress, at least.

I have one more day with this MacBook for the week, and can hopefully make something happen before then, but would also appreciate some eyes on the code, particularly if you may know what I'm missing that's preventing the Control Center from displaying anything.

ryanheise commented 4 years ago

Committed a fix for the nowPlayingInfo not showing. It turns out that I was calling it to early, and it has no effect unless audio is actually playing.

ryanheise commented 4 years ago

The iOS implementation is now more or less working in the iosdev branch. Thanks to @alexandergottlieb for contributing initialisation code and many others who provided helpful links to relevant iOS code, in particular @alexelisenko !

Note: If you want to use a flutter channel more recent than stable, you need to fix a bug in flutter_isolate (See pull request https://github.com/rmawatson/flutter_isolate/pull/27). It may be a better option to not have this dependency on flutter_isolate and just use the FlutterEngine API directly.

However, for now, this is all I am able to do, as the time has come to return the borrowed MacBook Pro.

I have implemented enough of what I needed for my own use cases, but it is still missing things like rendering album art and queue management, and there are bound to be some quirks and bugs.

Going forward, I plan to mainly accept pull requests for any remaining features, and I will leave the iOS code in the iosdev branch until the above issue with flutter_isolate is resolved.

alexandergottlieb commented 4 years ago

That's great news! I can probably have a crack at album art and queue management over the next couple of weeks.

ryanheise commented 4 years ago

Great! Thank you and look forward to that.

In other news, I contacted the author of flutter_isolate and he added me as a collaborator and uploader on his project so that I could accept and publish the pull request. Therefore, the iosdev branch should now work on the flutter beta channel.

I no longer have the MacBook, but I was able to compile and run things in my MacInCloud account and at least can confirm that there is no longer any error under beta, but I am unable to hear the audio in that environment so I would appreciate if anyone could test the iosdev (on flutter beta) on their iOS device or simulator.

If it works, I'll merge the branch to master and publish, even with the quirks and missing features, and hopefully that will bring in more bug reports and accelerate progress.

alexandergottlieb commented 4 years ago

@ryanheise I just tested the latest commit on an iPhone 5s. Playing/pausing via control centre is working.

With the AudioPlayer example, the audio pauses when the app is backgrounded, and resumes when the app resumes.

TextToSpeech is the same, except the sound stops working after the app resumes.

Video: https://youtu.be/ewQFY9po-9s

ryanheise commented 4 years ago

Hmm, I can't test this anymore, but when I tested it on the simulator, it seemed to work fine in the background. Did it also pause with the screen off? Do you see any play/pause logs via NSLog?

alexandergottlieb commented 4 years ago

I tried running on the Simulator (iPhone 11, iOS 13.2.2) and got an exception (trace below). It seems the command center actions cannot be void callbacks, so I've updated those to match the right signature (for now, always returning the success status). PR: #102

Show exception trace: ``` 2019-11-19 08:07:40.280938+0100 Runner[56811:447294] *** Assertion failure in -[MPRemoteCommand addTarget:action:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/MediaPlayer_Sim/MobileMusicPlayer-4017.200.33/SDK/MPRemoteCommand.m:134 2019-11-19 08:07:40.296804+0100 Runner[56811:447294] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Unsupported action method signature. Must return MPRemoteCommandHandlerStatus or take a completion handler as the second argument.' *** First throw call stack: ( 0 CoreFoundation 0x00007fff23c4f02e __exceptionPreprocess + 350 1 libobjc.A.dylib 0x00007fff50b97b20 objc_exception_throw + 48 2 CoreFoundation 0x00007fff23c4eda8 +[NSException raise:format:arguments:] + 88 3 Foundation 0x00007fff256c9b61 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 191 4 MediaPlayer 0x00007fff279daf40 -[MPRemoteCommand addTarget:action:] + 1154 5 audio_service 0x0000000105c6c5c5 -[AudioServicePlugin handleMethodCall:result:] + 1493 6 Flutter 0x0000000103c894fd __45-[FlutterMethodChannel setMethodCallHandler:]_block_invoke + 104 7 Flutter 0x0000000103c22ec0 _ZNK7flutter21PlatformMessageRouter21HandlePlatformMessageEN3fml6RefPtrINS_15PlatformMessageEEE + 166 8 Flutter 0x0000000103c26780 _ZN7flutter15PlatformViewIOS21HandlePlatformMessageEN3fml6RefPtrINS_15PlatformMessageEEE + 38 9 Flutter 0x0000000103c83db3 _ZNSt3__110__function6__funcIZN7flutter5Shell29OnEngineHandlePlatformMessageEN3fml6RefPtrINS2_15PlatformMessageEEEE4$_31NS_9allocatorIS8_EEFvvEEclEv + 57 10 Flutter 0x0000000103c353f1 _ZN3fml15MessageLoopImpl10FlushTasksENS_9FlushTypeE + 123 11 Flutter 0x0000000103c3a742 _ZN3fml17MessageLoopDarwin11OnTimerFireEP16__CFRunLoopTimerPS0_ + 26 12 CoreFoundation 0x00007fff23bb2944 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20 13 CoreFoundation 0x00007fff23bb2632 __CFRunLoopDoTimer + 1026 14 CoreFoundation 0x00007fff23bb1c8a __CFRunLoopDoTimers + 266 15 CoreFoundation 0x00007fff23bac9fe __CFRunLoopRun + 2238 16 CoreFoundation 0x00007fff23babe16 CFRunLoopRunSpecific + 438 17 GraphicsServices 0x00007fff38438bb0 GSEventRunModal + 65 18 UIKitCore 0x00007fff4784fb48 UIApplicationMain + 1621 19 Runner 0x00000001038c2db8 main + 72 20 libdyld.dylib 0x00007fff51a1dc25 start + 1 21 ??? 0x0000000000000001 0x0 + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException ```

With that it does work properly (plays in the background and with the screen off) in the simulator 🎉

... But not on a physical device. Testing on a 5s (12.4.2) and 6s Plus (13.1.3), the audio stops when the app is backgrounded/screen is switched off. Nothing printed to the console.

ryanheise commented 4 years ago

Thanks for that, it seems to work on the MacInCloud simulator, too. This is a good start, I think.

On a physical device, after starting the audio player and then pressing the home button to put the app into the background, and after as you reported the audio stops by itself, is the play/pause toggle button still available in the control center? And are you able to click that button while the app is in the background and hear the audio resume?

alexandergottlieb commented 4 years ago

The media controls go back to default after pressing the home button, tapping play does nothing:

ryanheise commented 4 years ago

I see. I am still tempted to merge the iOS branch as is, since having it not crash on iOS and work in foreground mode is itself an improvement. I'll start writing some documentation for iOS.

Next week I may be able to get my hands on a Mac and iPhone for some further testing so hopefully that will also help in cracking this mystery.

snaeji commented 4 years ago

Hey @ryanheise if you would like any help with testing i am all in. I have an iPhone 7 and a Mac. If you want me to test anything specific give me a heads up.

ryanheise commented 4 years ago

Thanks, @snaeji , much appreciated. Right now, the priority is to figure out why iOS is not allowing the example app to continue running in the background. Can you also test audio_player_service linked above and see if you can spot the difference between the two projects as to what audio_service is missing that would enable background execution on iOS?

bardiarastin commented 4 years ago

Hi, I'm just super happy that this is about to land. maybe this can help in keeping audio alive in the background? https://www.reddit.com/r/FlutterDev/comments/dvweng/request_for_community_help_flutter_music_player/f7vli3n?utm_source=share&utm_medium=web2x

alexandergottlieb commented 4 years ago

@bardiarastin that's it, nice find!

I added the below to Info.plist and it's working perfectly on device. Video

<key>UIBackgroundModes</key>
<array>
    <string>audio</string>
</array>

PR: #103

ryanheise commented 4 years ago

Hi @bardiarastin , @alexandergottlieb , I was SURE I had put those exact 4 lines into the Info.plist file, and just checking now, indeed I did:

https://github.com/ryanheise/audio_service/commit/992c4516937dea63332103a3b3aefb64a1e06ad2

So I'm not sure where those 4 lines went???

ryanheise commented 4 years ago

Ahah, I accidentally clobbered over it after I regenerated the iOS project to make it swift compatible! I've accepted your pull request.

I've almost finished writing up the iOS documentation.

ryanheise commented 4 years ago

By the way, @alexandergottlieb , I'm writing up a list of features and which ones work and don't work for Android and iOS. Do you see any sort of media controls on the lock screen on iOS that allow you to play/pause, etc, and do they work with the plugin?

alexandergottlieb commented 4 years ago

Yes, looking good. Play/pause works as expected on the lock screen, and we get received onPause over method channel printed to the console.

snaeji commented 4 years ago

Its running great on iPhone 7 iOS 13.2.3! Found one bug not related to the iOS side i think so i'll make an issue for it.

ryanheise commented 4 years ago

Version 0.5.0 has landed with iOS support!!! Thanks everyone who contributed. And thanks to everyone else for your patience :-) Of course there is still a lot more work to be done, but at least we now have a foundation to build on.

BTW, I'm sure 0.5.1 will be the version that actually works, but if there are any issues (e.g. if something happened in the merge), I'll find out tomorrow morning after I wake up ;-)

bardiarastin commented 4 years ago

@ryanheise awesome, I'm going to use this in a music app on both android and ios, our app gonna have a lot of users, I'll let you know if I face any issue.

ryanheise commented 4 years ago

Hi all, I've just published version 0.5.3 which adds a lot of missing iOS features including album art, queue management, updating nowPlayingInfo correctly from all states as well as fixing bugs on various pass-throughs that weren't working including onClick. Although, I'm not actually able to test onClick without an actual iPhone and headphones with a play/pause button (which I assume should be routed through to onClick).

One other core feature that's not implemented yet is the callback to handle when the user attempts to seek to a position from the control center.

Also, in case anyone is interested, I recently published a new audio player plugin called just_audio with iOS and Android support. You can read more about why I created it in #109 but basically:

I am considering building my own audio player plugin that is guaranteed to maintain compatibility with audio_service while also making it possible to build all the ultimate features we want in an audio player. So if you tell me what features would go into your ideal audio player, I may see what I can do.

yringler commented 4 years ago

@ryanheise, I just finished reading through the API docs, and I am very excited to switch to this package. There's a bunch of things I love about your API surface. Two things in particular I like:

  1. There's no play-from-source method. First, set the source. Then, play. It makes keeping track of state MUCH simpler.
  2. The set-source methods return (a future resolving to) the audio duration! Yes!
ryanheise commented 4 years ago

@yringler I'm glad you agree about the API, and thanks for posting the first feature request over on the new project page.

hacker1024 commented 4 years ago

macOS support for Flutter has been announced. How similar is it to iOS?

ryanheise commented 4 years ago

@hacker1024 I haven't taken a look at the Flutter plugin architecture for macOS yet, but macOS and iOS share a lot of the foundation framework libraries, so I would expect a lot of a plugin's platform code to be reusable.

Along with all the other Flutter news, I was excited to see this: https://marketplace.visualstudio.com/items?itemName=codemagic.remote-mac

hacker1024 commented 4 years ago

@hacker1024 I haven't taken a look at the Flutter plugin architecture for macOS yet, but macOS and iOS share a lot of the foundation framework libraries, so I would expect a lot of a plugin's platform code to be reusable.

Along with all the other Flutter news, I was excited to see this: https://marketplace.visualstudio.com/items?itemName=codemagic.remote-mac

That's good to hear.

Have you seen this? It could probably even run in the WSL 2.x on Windows. https://github.com/foxlet/macOS-Simple-KVM

There's also Darling, which can run macOS compiler tools on Linux/the WSL. https://github.com/darlinghq/darling

hacker1024 commented 4 years ago

Also, in case anyone is interested, I recently published a new audio player plugin called just_audio with iOS and Android support.

@ryanheise this looks nice, can it preload URLs further down in the queue so there's no wait when playing the next song?

ryanheise commented 4 years ago

@hacker1024 You can preload the next song by instantiating another instance of the audio player and calling setUrl in advance of when you need it to play.

I've heard of the KVM solution and it definitely would help me since what I need is a way to run and debug my code. However, I'm not sure if that would meet Apple's Terms of Service.

hacker1024 commented 4 years ago

However, I'm not sure if that would meet Apple's Terms of Service.

Probably not, but they deliberately turn a blind eye to this kind of thing - they're not going to sue you. In fact, certain Hackintosh kexts are actually whitelisted in macOS itself, so Apple help it happen.

mrxten commented 4 years ago

Hi, would be pretty good, if via your plugin we can configure hide/show NextTrack, PreviousTrack, SeekToPlaybackPosition for iOS notification.

bardiarastin commented 4 years ago

@ryanheise Hi, thanks for all awesome work you're putting on this I wanted to know how are things going with remaining ios stuff?

image

ryanheise commented 4 years ago

Thank you, @bardiarastin

There are some other items on my priority list right, such as Android v2 support, and also web support for just_audio, although I do also welcome pull requests especially on the iOS side to help the project move forward more swiftly (no pun intended!).

YaarPatandarAA commented 4 years ago

Using the Example on a physical iPhone iOS 13. I don't see the command center, is the example old and not updated to use command center?

ryanheise commented 4 years ago

I don't have a physical iPhone, but my understanding was that the command center is always accessible and there is nothing my plugin can do to make it inaccessible. Please correct me if this is not the case, as I don't have a physical device to check. Alternatively, do you mean you can see the command center, but you just don't see any media displayed on it when you call AudioServiceBackground.setMediaItem ?

YaarPatandarAA commented 4 years ago

The command center is there but it doesn’t show the current playing media. It is just blank and interactions with the buttons don’t do anything.

I am using the Example app from this code base. I have not altered it in any way. Just installing it on my phone.

I do see from previous comments that the command center does indeed work.

minhdev2017 commented 4 years ago

ios not show music control bar, how to fix please, sr my bad english :v

YaarPatandarAA commented 4 years ago

@ryanheise after some checking of old commits the iOS Command Center broke at commit 7578d7745ee7546302f5f7317575be9740279518

The change that broke it is changing flutter_tts: ^0.7.0 to flutter_tts: ^0.8.5. Reverting to the old version fixes the Example App.

I tested on a Physical iPhone 11 Pro Max iOS 13.3.1 with Flutter:

[✓] Flutter (Channel stable, v1.12.13+hotfix.8, on Mac OS X 10.15.1 19B88, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.3.1)
[✓] Android Studio (version 3.5)
[✓] VS Code (version 1.42.0)
ryanheise commented 4 years ago

@YaarPatandarAA , that's certainly interesting, thanks for isolating the specific plugin and version.

I don't see anything obviously problematic with flutter_tts 0.8.5's code, though. Perhaps it is related to its build/configuration files.

Note: This particular issue is now being tracked in #202 .

I am closing this "iOS Support" issue finally, now that it has for the most part served its original purpose. From now on I would encourage people to open new issues for specific iOS features or bugs. It almost feels sad to close it after such a long journey, and with all of the suggestions and contributions from you all. It was a true community effort. Thank you!

YaarPatandarAA commented 4 years ago

Not sure if this counts as Apple CarPlay support but here is this package working on Apple CarPlay. The shown buttons also work, this screen is under Now Playing app on Apple CarPlay. I know there is way more that can be done with Apple CarPlay than just this, but it's a start. 👍🏻

20200423_194851

snaeji commented 4 years ago

@YaarPatandarAA can you tell me what this package is? It's just bold not hyperlinked 😄

YaarPatandarAA commented 4 years ago

@YaarPatandarAA can you tell me what this package is? It's just bold not hyperlinked 😄

This package refers to this package on which we are commenting on, in this packages issue. https://pub.dev/packages/audio_service

snaeji commented 4 years ago

@YaarPatandarAA Thanks for clearing that! I was reading it in a completely different way 👍

ryanheise commented 4 years ago

Ah, that makes perfect sense :-) I also had the same misunderstanding as @snaeji

This plugin might now actually have better support for Apple CarPlay than for Android Auto, which is an interesting twist.

nazdream commented 3 years ago

Hey there. I am working on a project which requires bookmarking functionality for both iOS and Android. I am wondering, has anyone managed to add "bookmarkCommand" for iOS? I would be very thankful if there is anyone who did that and can share their experience.

github-actions[bot] commented 3 years ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs, or use StackOverflow if you need help with audio_service.