Author Topic: BASS for iOS (iPhone/iPad)  (Read 416921 times)

Josh

  • Guest
Re: BASS for iOS (iPhone/iPad)
« Reply #400 on: 24 Feb '12 - 03:33 »
The update also adds the previously mentioned support for buffered file and internet streams with CoreAudio codecs. That seems to be working nicely so far, but troublesome cases are always a possibility, so please report if you encounter any any.

Are there any code examples on how to play a music file from the device music library without importing the file data locally or am I missing the intent of the above comment?

Ian @ un4seen

  • Administrator
  • Posts: 19489
Re: BASS for iOS (iPhone/iPad)
« Reply #401 on: 24 Feb '12 - 15:59 »
I have questions about BPM_Beat function. I was just wondering which way would cost less ressources. I want to retrieve the position in milliseconds of a beat in real-time so I use BASS_FX_BPM_CallbackSet. But I only want to retrieve that when I press a button in my app. Using the Callback_Set function it will retrieve the value any time there is a beat detected e.g once the button pressed it triggers the callback until I reset it. My question is what's better between leaving the callback retrieve the beat every time and just remove the callback when I don't need it anymore?
It means that when I press a button it will detect the beat just once and stop the callback, then if I press the button again it will detect the beat again

In other words will the use of BASS_FX_BPM_BeatCallbackSet then BASS_FX_BPM_BeatCallbackReset cost more ressources than a simple call of BASS_FX_BPM_CallbackSet or it doesn't really matter?

Do you mean BASS_FX_BPM_BeatFree rather than BASS_FX_BPM_BeatCallbackReset? The former stops the beat detection and releases its resources, while the latter just resets the detection and continues (eg. after seeking). I guess stopping and starting the beat detection would generally be more efficient, depending on how often you need to do that. If you're constantly stopping and starting the beat detection, then it may be better to just leave it on (it isn't very CPU-intensive).

First to describe overall what I'm doing, I'm streaming song files that are downloaded by a separate part of the app, using BASS_StreamCreateFileUser. The files may either be fully downloaded, or may be in the process of downloading when BASS_StreamCreateFileUser is called. They are read using DECODE streams fed into an output stream to obtain gapless playback. This works 100% perfectly if the files are all on disk and not in the process of downloading when they are played.

Please post your BASS_StreamCreateFileUser call and BASS_FILEPROCS functions to show exactly what you are doing. I will then be in a better position to answer your questions :)

It sounds like you should be using the STREAMFILE_BUFFER file system. When using that system, BASS pre-allocates a buffer for the file and it won't go beyond that, so your FILELENPROC function should give the total size even if it isn't currently all available. Whenever the FILEREADPROC function has no data available, it should wait for some (if there is more to come). The FILECLOSEPROC function should cancel that waiting, as the stream can't be freed until the FILEREADPROC returns.

Are there any code examples on how to play a music file from the device music library without importing the file data locally or am I missing the intent of the above comment?

The recent BASS update added the ability to use the BASS_StreamCreateURL and BASS_StreamCreateFileUser (with buffered file system) functions with CoreAudio codecs, which simplifies playing AAC radio streams, for example. It doesn't affect playing from the device's music library; as far as I know, that still requires copying the file into the app's sandbox.

Delphinus

  • Posts: 39
Re: BASS for iOS (iPhone/iPad)
« Reply #402 on: 24 Feb '12 - 17:22 »
Okay it's good to know. Thanks. ;)

I have other questions: I want to play an mp3 file buffer by buffer I don't know how to do it. I have a stream to play the mp3 file and what I want is when I press a button it pauses the stream playback (easy) then retrieve a buffer of the position of the mp3 file when paused.

I want to simulate a jog wheel in fact and I don't know which function do I have to use. I tried BASS_ChannelGetData but maybe it's not the right solution.

I just want to read a mp3 file buffer by buffer in a forward or reverse way.

Any idea?

DrummerB

  • Posts: 19
Re: BASS for iOS (iPhone/iPad)
« Reply #403 on: 24 Feb '12 - 18:03 »
One of my users contacted me, because for some music files my app seems to display wrong durations.

He sent me this example:
http://upload.fabali.net/media/SetFireToTheRain.mp3

iTunes, QuickTime or the iPod player have no issues playing it and displaying the correct duration (4:03). My app however displays 15:44. I did some tests and the duration function returns a wrong value:

Code: [Select]
float sec = BASS_ChannelBytes2Seconds(channel, BASS_ChannelGetLength(channel, BASS_POS_BYTE));
This returns 944.039185 seconds (15:44). I'm not sure if BASS is doing something wrong, the sound file is corrupted or my channel is somehow messed up. The app however works for every other file I ever tested and this is the first report about this problem (the app has been released a year ago).

I'm getting a length of 4:03 from BASS too here. What BASS version are you using? If it isn't the latest (in the 1st post), please give that a try and see if you still have the problem with it.


I'm using the latest version. I've come closer to tracking down the issue. My app is importing the sound files from the user's music library (using TSLibraryImport). I think the file is somehow corrupted during this process. To verify this assumption, I once again imported the song into my app and then saved it to my Mac using XCode. When I play this file, QuickTime (and other players) show a total duration of 6:17. They just play the song normally (4:03) and then play silence until the end. If I load this file into a barebone BASS test project BASS returns a length of 944 seconds (15:44). However this problem doesn't seem to happen with other song file, just this one. The user who sent it to me, said he has this issue with the sound files he creates using a Mac app called Piezo.

Original file: Download
Imported (corrupted?) file: Download
Barebone test project: Download

einsteinx2

  • Posts: 67
Re: BASS for iOS (iPhone/iPad)
« Reply #404 on: 24 Feb '12 - 21:25 »
Ian, I sent you a private message with the entirety of my bass wrapper class, rather than just posting fragments. Hopefully I'm doing something really obviously wrong. :P

Ian @ un4seen

  • Administrator
  • Posts: 19489
Re: BASS for iOS (iPhone/iPad)
« Reply #405 on: 27 Feb '12 - 17:26 »
I'm using the latest version. I've come closer to tracking down the issue. My app is importing the sound files from the user's music library (using TSLibraryImport). I think the file is somehow corrupted during this process. To verify this assumption, I once again imported the song into my app and then saved it to my Mac using XCode. When I play this file, QuickTime (and other players) show a total duration of 6:17. They just play the song normally (4:03) and then play silence until the end. If I load this file into a barebone BASS test project BASS returns a length of 944 seconds (15:44). However this problem doesn't seem to happen with other song file, just this one. The user who sent it to me, said he has this issue with the sound files he creates using a Mac app called Piezo.

Original file: Download
Imported (corrupted?) file: Download
Barebone test project: Download

That is a VBR MP3 file and the original has a "Xing" header containing length info, but that header appears to have been stripped out in the imported version, so the length is estimated by BASS in that case. To get around that, you can add the BASS_STREAM_PRESCAN flag to your BASS_StreamCreateFile call.

Ian, I sent you a private message with the entirety of my bass wrapper class, rather than just posting fragments. Hopefully I'm doing something really obviously wrong. :P

Got it. I haven't looked at the code in great detail yet, but I do see that you're still using the STREAMFILE_NOBUFFER file system. To take advantage of the updated stuff, you should switch to the buffered file system, eg. STREAMFILE_BUFFER. Let me know if you still have problems after doing that (see my previous reply for callback requirements), and I'll take a closer look :)

einsteinx2

  • Posts: 67
Re: BASS for iOS (iPhone/iPad)
« Reply #406 on: 27 Feb '12 - 21:39 »
Ian, I sent you a private message with the entirety of my bass wrapper class, rather than just posting fragments. Hopefully I'm doing something really obviously wrong. :P

Got it. I haven't looked at the code in great detail yet, but I do see that you're still using the STREAMFILE_NOBUFFER file system. To take advantage of the updated stuff, you should switch to the buffered file system, eg. STREAMFILE_BUFFER. Let me know if you still have problems after doing that (see my previous reply for callback requirements), and I'll take a closer look :)

I did switch to BUFFERED to test however it was still stopping when reaching the end of the file for some reason, rather than buffering and waiting. I will do some more testing and report back.

Ian @ un4seen

  • Administrator
  • Posts: 19489
Re: BASS for iOS (iPhone/iPad)
« Reply #407 on: 28 Feb '12 - 15:01 »
Did you also update the callback functions when switching to the BUFFERED system? If not, please try doing what I described in my earlier reply (eg. waiting for data in the FILEREADPROC) and let me know if you still have any trouble with it.

DrummerB

  • Posts: 19
Re: BASS for iOS (iPhone/iPad)
« Reply #408 on: 28 Feb '12 - 22:14 »
Thank you very much, Ian!
Adding BASS_STREAM_PRESCAN solved the problem.

einsteinx2

  • Posts: 67
Re: BASS for iOS (iPhone/iPad)
« Reply #409 on: 29 Feb '12 - 21:54 »
Did you also update the callback functions when switching to the BUFFERED system? If not, please try doing what I described in my earlier reply (eg. waiting for data in the FILEREADPROC) and let me know if you still have any trouble with it.

I had completely misunderstood how BUFFERED was supposed to work. I had thought it waited automatically or something. I switched to BUFFERED and then rewrote it so that is does a sleep loop in the read proc whenever there was not enough data for a read. Well actually it rolls back the file pointer position, waits until the specified amount of file is available (or the file finishes caching) and then does the read again. So it always returns a full read. Then I'm setting a flag in the user object to exit the loop when the file close proc runs, in case it's waiting when I call a BASS_Free. It's working beautifully!

I was also able to solve my other issue. What was happening is that if there was not enough of the file right at the beginning to do the reads necessary for the stream to be created, then it would sit in that read wait loop and freeze the thread that called StreamCreateFileUser. In this case, the main thread, so the whole UI would freeze. Instead, I created a dedicated thread for creating file streams. So in those cases, it still pauses that thread, but it's pausing that dedicated thread instead of the main thread. Et voilą! No more freezes :)

So, so far so good. I'll let you know if I run into any other issues, but it seems to be working well now. Thanks!
« Last Edit: 29 Feb '12 - 21:57 by einsteinx2 »

einsteinx2

  • Posts: 67
Re: BASS for iOS (iPhone/iPad)
« Reply #410 on: 29 Feb '12 - 22:00 »
One quick question though, is there any way to control the size of the file stream buffer? It seems to be unrelated to the playback buffer. I noticed it seems to buffer a couple of MB (for instance it will buffer an entire MP3 into memory). Since iOS devices, especially older ones, are very memory constrained, I'd much rather have it only buffer about 500KB. Is there a way to set that?

Ian @ un4seen

  • Administrator
  • Posts: 19489
Re: BASS for iOS (iPhone/iPad)
« Reply #411 on: 1 Mar '12 - 16:06 »
Good to hear you have got it working. Note you don't actually need to wait for the full requested amount in your FILEREADPROC; it is fine to return less, just not nothing :)

Regarding the file buffer size, you can limit that (according to the BASS_CONFIG_NET_BUFFER setting) by using the BASS_STREAM_BLOCK flag, but note that will disable seeking. If seeking is needed, perhaps you could just disable it until the download is complete, and then replace the buffered stream with a stream created from the local file (via BASS_StreamCreateFile) at the first seek.

By the way, where are you downloading the file from? If it is a standard HTTP or FTP server, perhaps you can replace all the BASS_StreamCreateFileUser stuff (and your download stuff) with a BASS_StreamCreateURL call, and provide a DOWNLOADPROC function to receive the downloaded data for your local copy.

einsteinx2

  • Posts: 67
Re: BASS for iOS (iPhone/iPad)
« Reply #412 on: 6 Mar '12 - 21:04 »
Good to hear you have got it working. Note you don't actually need to wait for the full requested amount in your FILEREADPROC; it is fine to return less, just not nothing :)
Right now it's been working well just waiting for all available data, but I'll play around with returning just what's available and only waiting on 0 bytes read to see if I get any less pausing on poor connections.

Regarding the file buffer size, you can limit that (according to the BASS_CONFIG_NET_BUFFER setting) by using the BASS_STREAM_BLOCK flag, but note that will disable seeking. If seeking is needed, perhaps you could just disable it until the download is complete, and then replace the buffered stream with a stream created from the local file (via BASS_StreamCreateFile) at the first seek.
Because on slower connections, the song can be buffering for almost the entire play time, using the STREAM_BLOCK setting is unfortunately not an option, as seeking needs to work. Is there any way you could possibly expose a setting to limit the amount of buffering done without BLOCK reads in a future BASS update or is there a design limitation preventing that?

By the way, where are you downloading the file from? If it is a standard HTTP or FTP server, perhaps you can replace all the BASS_StreamCreateFileUser stuff (and your download stuff) with a BASS_StreamCreateURL call, and provide a DOWNLOADPROC function to receive the downloaded data for your local copy.
The app is iSub, a Subsonic client. Unfortunately iSub already has an advanced caching mechanism implemented including prebuffering of the next song(s) and manual song caching that necessitates the downloading functionality to be separate from the audio player. It works quite well now, really the only issue I have is not being able to control the read stream buffer size, but even that isn't a huge problem. It would just be nice to limit it lower to help prevent low memory conditions, especially when the next stream is queued and ready to go. So far it hasn't been a huge problem, but if I have to I can always use logic in the read proc to limit the amount of data fed to the stream buffer. It would just be easier to set a setting in BASS instead of writing more logic that's all.

bcgilliom

  • Posts: 2
Re: BASS for iOS (iPhone/iPad)
« Reply #413 on: 7 Mar '12 - 19:57 »
Hello,

I am using BASS to play music for iOS games, and everything works as expected except that background iPod audio gets paused immediately when BASS_Init is called.

My app audio category is set to ambient (not solo ambient) and I have tried setting BASS_CONFIG_IOS_MIXAUDIO to both 1 and 4.  I have the latest version of the lib (Feb 17th) and am building with the iOS 5 sdk with a deployment target of 4.0. 

Any help would be greatly appreciated!!

Ian @ un4seen

  • Administrator
  • Posts: 19489
Re: BASS for iOS (iPhone/iPad)
« Reply #414 on: 8 Mar '12 - 16:11 »
When using an "ambient" session category, you should set BASS_CONFIG_IOS_MIXAUDIO to 5 to have other audio mixed with yours... 5 results in the kAudioSessionCategory_AmbientSound category (other apps are mixed), while 4 results in the kAudioSessionCategory_SoloAmbientSound category (other apps are silenced).

In the case of setting BASS_CONFIG_IOS_MIXAUDIO to 1, the problem in this case seems to be related to how the kAudioSessionProperty_OverrideCategoryMixWithOthers and kAudioSessionProperty_OtherMixableAudioShouldDuck options interact. I have put an updated BASS build up in the 1st post, with a little change to how that stuff is set. Please let me know if you still see the problem happening with that.

bcgilliom

  • Posts: 2
Re: BASS for iOS (iPhone/iPad)
« Reply #415 on: 9 Mar '12 - 00:55 »
When using an "ambient" session category, you should set BASS_CONFIG_IOS_MIXAUDIO to 5 to have other audio mixed with yours... 5 results in the kAudioSessionCategory_AmbientSound category (other apps are mixed), while 4 results in the kAudioSessionCategory_SoloAmbientSound category (other apps are silenced).

In the case of setting BASS_CONFIG_IOS_MIXAUDIO to 1, the problem in this case seems to be related to how the kAudioSessionProperty_OverrideCategoryMixWithOthers and kAudioSessionProperty_OtherMixableAudioShouldDuck options interact. I have put an updated BASS build up in the 1st post, with a little change to how that stuff is set. Please let me know if you still see the problem happening with that.

That did the trick! You, sir, are a gentleman and a scholar.  Thank you for the quick update.

HyperNovaSoftware

  • Posts: 54
Re: BASS for iOS (iPhone/iPad)
« Reply #416 on: 13 Mar '12 - 12:33 »
How can I debug this crash?  I've seen this happen 5 or 6 times over the last few months in the course of testing my app.

Thread 15 name:  Dispatch queue: com.apple.root.default-priority
Thread 15 Crashed:
0   libobjc.A.dylib                  0x35782fbc objc_msgSend + 16
1   CoreFoundation                   0x33fb5020 CFRetain + 76
2   CFNetwork                        0x33402f44 HostBase::lock() + 8
3   CFNetwork                        0x3340268a DispatchHost::performInvocation(void const*) + 6
4   CFNetwork                        0x334021dc __setupTCPConnection_block_invoke_2 + 284
5   libsystem_network.dylib          0x33465ad0 __tcp_connection_notify_complete_block_invoke_1 + 12
6   libdispatch.dylib                0x37343d4e _dispatch_call_block_and_release + 6
7   libdispatch.dylib                0x3734f79c _dispatch_worker_thread2 + 256
8   libsystem_c.dylib                0x34ea21c8 _pthread_wqthread + 288
9   libsystem_c.dylib                0x34ea209c start_wqthread + 0

Ian @ un4seen

  • Administrator
  • Posts: 19489
Re: BASS for iOS (iPhone/iPad)
« Reply #417 on: 13 Mar '12 - 15:49 »
There doesn't appear to be any mention of your app or BASS in that call stack, which makes it trickier to locate the problem. From the mention of CFNetwork, it may be related to an internet connection. Do you have call stacks from the other threads too?

Also, what BASS version are you using? You can use BASS_GetVersion to check that. If it isn't the latest, please first try updating to that (in the 1st post).

HyperNovaSoftware

  • Posts: 54
Re: BASS for iOS (iPhone/iPad)
« Reply #418 on: 13 Mar '12 - 16:44 »
There doesn't appear to be any mention of your app or BASS in that call stack, which makes it trickier to locate the problem. From the mention of CFNetwork, it may be related to an internet connection. Do you have call stacks from the other threads too?

Also, what BASS version are you using? You can use BASS_GetVersion to check that. If it isn't the latest, please first try updating to that (in the 1st post).

BASS_GetVersion reports 2.4.8.11.

The only network activity that is occurring at the time of the crash (as far as I can tell - my app is in the foreground and no other apps are accessing the network) is 6 Internet streams being played using BASS_ChannelPlay.

I've attached the crash log in it's entirety.

Ian @ un4seen

  • Administrator
  • Posts: 19489
Re: BASS for iOS (iPhone/iPad)
« Reply #419 on: 13 Mar '12 - 17:28 »
OK. The current build is 2.4.8.13, so please give that a try and see if the crash still happens. If it does, I'll send you a debug version to try to locate it.

mix1009

  • Posts: 9
Re: BASS for iOS (iPhone/iPad)
« Reply #420 on: 14 Mar '12 - 05:29 »
I'm using BASS_StreamCreateFileUser(STREAMFILE_BUFFER ...) and BASS_FILEPROCS to play audio file
while the file is being copied from iPod library. LenProc returns the file size to be copied (precalculated), and read and seek
procs blocks(waits) if the position is not copied yet. It works but seek only work in beginning parts of the track.

I also tried using BASS_StreamCreateFile with file size set to zero or file size(precalculated). But the seek also only works
for beginning parts of the track.

For audio tracks it's not too bad to copy the file from iPod Library then play. But for podcasts and audiobooks the delay is too long. What would be the best method to implement audio playback from iPod Library?

I've used the latest library (March 8th)

HyperNovaSoftware

  • Posts: 54
Re: BASS for iOS (iPhone/iPad)
« Reply #421 on: 14 Mar '12 - 14:34 »
There is one thing that I've been meaning to ask about.

I use the following code to adjust the overall app volume:

Code: [Select]
    (BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, (DWORD)(self.appVolumeLevel * 10000.00f)));

where appVolumeLevel is defined as float.

The volume does not adjust in a linear fashion.  It changes slightly but when it approaches the upper and lower limits, it changes dramatically.

Ian @ un4seen

  • Administrator
  • Posts: 19489
Re: BASS for iOS (iPhone/iPad)
« Reply #422 on: 14 Mar '12 - 15:28 »
I'm using BASS_StreamCreateFileUser(STREAMFILE_BUFFER ...) and BASS_FILEPROCS to play audio file
while the file is being copied from iPod library. LenProc returns the file size to be copied (precalculated), and read and seek
procs blocks(waits) if the position is not copied yet. It works but seek only work in beginning parts of the track.

I also tried using BASS_StreamCreateFile with file size set to zero or file size(precalculated). But the seek also only works
for beginning parts of the track.

For audio tracks it's not too bad to copy the file from iPod Library then play. But for podcasts and audiobooks the delay is too long. What would be the best method to implement audio playback from iPod Library?

The FILESEEKPROC isn't actually used by the STREAMFILE_BUFFER system. BASS will "download" the file data via your FILEREADPROC, and the availability of seeking will depend on how far that has progressed at the time of the seek request (BASS_ChannelSetPosition call). BASS_StreamGetFilePosition (BASS_FILEPOS_DOWNLOAD) can be used to check that.

How are you copying the file from the library to your app's sandbox? I think it is generally a pretty quick process, so perhaps you could complete that and then pass the file to BASS_StreamCreateFile instead of using BASS_StreamCreateFileUser.

I use the following code to adjust the overall app volume:

Code: [Select]
    (BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, (DWORD)(self.appVolumeLevel * 10000.00f)));

where appVolumeLevel is defined as float.

The volume does not adjust in a linear fashion.  It changes slightly but when it approaches the upper and lower limits, it changes dramatically.

The BASS_CONFIG_GVOL_STREAM setting does have a linear effect on the level, but the audible effect won't be linear because the level adjustments need to be more logarithmic for that. To make them logarithmic, you could do something like this...

Code: [Select]
float level=(self.appVolumeLevel?pow10(self.appVolumeLevel*-dbrange/20):0);
BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, (DWORD)(level * 10000.00f));

Where "dbrange" is the dB range of your volume control. Something like 30 could be a good number for that.

einsteinx2

  • Posts: 67
Re: BASS for iOS (iPhone/iPad)
« Reply #423 on: 15 Mar '12 - 23:51 »
Ian, I ended up switching back to NOBUFFER streams because the memory usage of BUFFER streams was not workable on an iOS device in my use case. I ended up implementing a ring buffer to buffer my NOBUFFER file streams so that the BASS output buffer can remain fairly small for seeking to be quick, but I can still have a large buffer to prevent underruns. It's working very well, no issues there, that just brings me to the issue I discovered today:

I noticed today that when playing FLAC files, the BASS_ChannelGetData function works differently than for all other types of files. For all other file types, if the read proc returns 0 bytes, then BASS_ChannelGetData simply returns 0 bytes. However, for FLAC files, BASS_ChannelGetData blocks until it can return the number of bytes requested.

The causes a problem because it immediately stops audio output even if my ring buffer is full, it breaks my code that pauses the playback temporarily when there are underruns and the ring buffer is empty to prevent choppy playback on poor connections, and it sits at 100% cpu utilization while waiting for data because it bounces back and forth between the file len proc and file read proc.

Also, if I don't pause and wait for more data to be downloaded, BASS_ChannelGetData will keep blocking for each read and produce stuttering and even worse, after the connection is fast again there is still massive stuttering until I seek. My pausing code eliminates that problem and works fine for all file types that allow 0 to be returned by BASS_ChannelGetData.

Is there some reason that the behavior of the user file stream procs is different for FLAC than all other formats? I understand it's a plugin, but so are the CoreAudio codecs (correct?) and they work fine.

Could you fix it so that when reading FLAC files, the read proc is not retried over and over until data is available and it simply returns 0 for BASS_ChannelGetData like other file types do? That would completely fix the last of the issues I'm experiencing.
« Last Edit: 15 Mar '12 - 23:54 by einsteinx2 »

einsteinx2

  • Posts: 67
Re: BASS for iOS (iPhone/iPad)
« Reply #424 on: 16 Mar '12 - 00:13 »
I'm testing out adding some extra logic to check for the song actually starting (i.e. after the seek proc gets a seek to position 0) so that I can try putting the pause logic back into the file stream read proc (currently it's in my output stream read proc). I couldn't before because at the beginning 0 byte reads are expected.

So a fix may not be necessary on your side, but it would still be nice to have consistant behavior unless there's some technical reason it works this way.

-------------------

EDIT: Unfortunately that didn't work. If I try and do a BASS_free() while it's waiting in the read proc, even though I set a boolean first that causes the wait loop to end, it will block forever on the BASS_free(), bouncing back and forth between the len and read procs instead of just ending the stream. I really just need BASS_ChannelGetData to return 0 like for all other file types so I can keep the read proc for the file streams doing simple file reads and keep my other logic in the output channels proc, as that seems to work perfectly.

----------------------

EDIT2: I was able to code around the issue, but it's kind of hacky.
« Last Edit: 16 Mar '12 - 01:39 by einsteinx2 »