diff options
Diffstat (limited to 'src/ios.m')
-rw-r--r-- | src/ios.m | 127 |
1 files changed, 127 insertions, 0 deletions
@@ -24,11 +24,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
24 | #include "app.h" | 24 | #include "app.h" |
25 | #include "ui/command.h" | 25 | #include "ui/command.h" |
26 | #include "ui/window.h" | 26 | #include "ui/window.h" |
27 | |||
28 | #include <the_Foundation/file.h> | ||
29 | #include <the_Foundation/fileinfo.h> | ||
30 | #include <the_Foundation/path.h> | ||
27 | #include <SDL_events.h> | 31 | #include <SDL_events.h> |
28 | #include <SDL_syswm.h> | 32 | #include <SDL_syswm.h> |
33 | #include <SDL_timer.h> | ||
29 | 34 | ||
30 | #import <UIKit/UIKit.h> | 35 | #import <UIKit/UIKit.h> |
31 | #import <CoreHaptics/CoreHaptics.h> | 36 | #import <CoreHaptics/CoreHaptics.h> |
37 | #import <AVFAudio/AVFAudio.h> | ||
32 | 38 | ||
33 | static iBool isSystemDarkMode_ = iFalse; | 39 | static iBool isSystemDarkMode_ = iFalse; |
34 | static iBool isPhone_ = iFalse; | 40 | static iBool isPhone_ = iFalse; |
@@ -223,6 +229,7 @@ void setupApplication_iOS(void) { | |||
223 | selector:@selector(keyboardOffScreen:) | 229 | selector:@selector(keyboardOffScreen:) |
224 | name:UIKeyboardWillHideNotification | 230 | name:UIKeyboardWillHideNotification |
225 | object:nil]; | 231 | object:nil]; |
232 | [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; | ||
226 | } | 233 | } |
227 | 234 | ||
228 | static iBool isDarkMode_(iWindow *window) { | 235 | static iBool isDarkMode_(iWindow *window) { |
@@ -309,3 +316,123 @@ void exportDownloadedFile_iOS(const iString *path) { | |||
309 | [appState_ setFileBeingSaved:path]; | 316 | [appState_ setFileBeingSaved:path]; |
310 | [viewController_(get_Window()) presentViewController:picker animated:YES completion:nil]; | 317 | [viewController_(get_Window()) presentViewController:picker animated:YES completion:nil]; |
311 | } | 318 | } |
319 | |||
320 | /*----------------------------------------------------------------------------------------------*/ | ||
321 | |||
322 | enum iAVFAudioPlayerState { | ||
323 | initialized_AVFAudioPlayerState, | ||
324 | playing_AVFAudioPlayerState, | ||
325 | paused_AVFAudioPlayerState | ||
326 | }; | ||
327 | |||
328 | struct Impl_AVFAudioPlayer { | ||
329 | iString cacheFilePath; | ||
330 | AVAudioPlayer *player; | ||
331 | float volume; | ||
332 | enum iAVFAudioPlayerState state; | ||
333 | }; | ||
334 | |||
335 | iDefineTypeConstruction(AVFAudioPlayer) | ||
336 | |||
337 | void init_AVFAudioPlayer(iAVFAudioPlayer *d) { | ||
338 | init_String(&d->cacheFilePath); | ||
339 | d->player = NULL; | ||
340 | d->volume = 1.0f; | ||
341 | d->state = initialized_AVFAudioPlayerState; | ||
342 | } | ||
343 | |||
344 | void deinit_AVFAudioPlayer(iAVFAudioPlayer *d) { | ||
345 | setInput_AVFAudioPlayer(d, NULL, NULL); | ||
346 | } | ||
347 | |||
348 | static const char *cacheDir_ = "~/Library/Caches/Audio"; | ||
349 | |||
350 | static const char *fileExt_(const iString *mimeType) { | ||
351 | /* Media types that AVFAudioPlayer will try to play. */ | ||
352 | if (startsWithCase_String(mimeType, "audio/aiff") || | ||
353 | startsWithCase_String(mimeType, "audio/x-aiff")) { | ||
354 | return ".aiff"; | ||
355 | } | ||
356 | if (startsWithCase_String(mimeType, "audio/3gpp")) return ".3gpp"; | ||
357 | if (startsWithCase_String(mimeType, "audio/mpeg")) return ".mp3"; | ||
358 | if (startsWithCase_String(mimeType, "audio/mp3")) return ".mp3"; | ||
359 | if (startsWithCase_String(mimeType, "audio/mp4")) return ".mp4"; | ||
360 | if (startsWithCase_String(mimeType, "audio/mpeg4")) return ".mp4"; | ||
361 | if (startsWithCase_String(mimeType, "audio/aac")) return ".aac"; | ||
362 | return ""; | ||
363 | } | ||
364 | |||
365 | iBool setInput_AVFAudioPlayer(iAVFAudioPlayer *d, const iString *mimeType, const iBlock *audioFileData) { | ||
366 | if (!isEmpty_String(&d->cacheFilePath)) { | ||
367 | remove(cstr_String(&d->cacheFilePath)); | ||
368 | clear_String(&d->cacheFilePath); | ||
369 | } | ||
370 | if (d->player) { | ||
371 | d->player = nil; | ||
372 | } | ||
373 | if (mimeType && audioFileData && iCmpStr(fileExt_(mimeType), "")) { | ||
374 | makeDirs_Path(collectNewCStr_String(cacheDir_)); | ||
375 | iFile *f = new_File(collectNewFormat_String("%s/%u%s", cacheDir_, SDL_GetTicks(), fileExt_(mimeType))); | ||
376 | if (open_File(f, writeOnly_FileMode)) { | ||
377 | write_File(f, audioFileData); | ||
378 | set_String(&d->cacheFilePath, path_File(f)); | ||
379 | NSError *error = nil; | ||
380 | d->player = [[AVAudioPlayer alloc] | ||
381 | initWithContentsOfURL:[NSURL fileURLWithPath: | ||
382 | [NSString stringWithUTF8String:cstr_String(&d->cacheFilePath)]] | ||
383 | error:&error]; | ||
384 | if (error) { | ||
385 | d->player = nil; | ||
386 | } | ||
387 | [d->player setVolume:d->volume]; | ||
388 | } | ||
389 | iRelease(f); | ||
390 | } | ||
391 | return d->player != nil; | ||
392 | } | ||
393 | |||
394 | void play_AVFAudioPlayer(iAVFAudioPlayer *d) { | ||
395 | if (d->state != playing_AVFAudioPlayerState) { | ||
396 | [d->player play]; | ||
397 | d->state = playing_AVFAudioPlayerState; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | void stop_AVFAudioPlayer(iAVFAudioPlayer *d) { | ||
402 | [d->player stop]; | ||
403 | d->state = initialized_AVFAudioPlayerState; | ||
404 | } | ||
405 | |||
406 | void setPaused_AVFAudioPlayer(iAVFAudioPlayer *d, iBool paused) { | ||
407 | if (paused && d->state != paused_AVFAudioPlayerState) { | ||
408 | [d->player pause]; | ||
409 | d->state = paused_AVFAudioPlayerState; | ||
410 | } | ||
411 | else if (!paused && d->state != playing_AVFAudioPlayerState) { | ||
412 | [d->player play]; | ||
413 | d->state = playing_AVFAudioPlayerState; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | void setVolume_AVFAudioPlayer(iAVFAudioPlayer *d, float volume) { | ||
418 | d->volume = volume; | ||
419 | if (d->player) { | ||
420 | [d->player setVolume:volume]; | ||
421 | } | ||
422 | } | ||
423 | |||
424 | double currentTime_AVFAudioPlayer(const iAVFAudioPlayer *d) { | ||
425 | return [d->player currentTime]; | ||
426 | } | ||
427 | |||
428 | double duration_AVFAudioPlayer(const iAVFAudioPlayer *d) { | ||
429 | return [d->player duration]; | ||
430 | } | ||
431 | |||
432 | iBool isStarted_AVFAudioPlayer(const iAVFAudioPlayer *d) { | ||
433 | return d->state != initialized_AVFAudioPlayerState; | ||
434 | } | ||
435 | |||
436 | iBool isPaused_AVFAudioPlayer(const iAVFAudioPlayer *d) { | ||
437 | return d->state == paused_AVFAudioPlayerState; | ||
438 | } | ||