We have built a simple proof of concept app using Twilio. The app plays very short MP3 files upon demand. We are consistently seeing a delay of about 5 seconds before the audio plays. Our audio files have no delay/silence at the beginning. Our files are very small. As a test I have visited the MP3 url in my browser and it responds immediately i.e. there is no apparent delay introduced by our server that serves the files. Can anyone explain why this might be happening? This is a trial account, so I thought that maybe Twilio introduces an intentional delay on trial accounts, but I can't find any reference to that in the docs. Thanks.
I resolved this. I had mistakenly specified finishOnKey instead of numDigits, which screwed things up.
Related
I have a need to play LIVE audio to enqueued twilio calls (instead of playing hold music from an mp3 file for instance).
I've tried pointing the hold music to a live mp3 stream (icecast), which didn't work.
The only thing I can think of is to start a conference, put a call into it that is sending the audio I need to be played on hold, and then on-hold calls are placed (muted) into that conference.
Doesn't seem like best way, and I'd like to avoid conference costs though (there are millions of minutes per month of on-hold time).
Is there a more elegant solution for this problem?
Twilio developer evangelist here.
As far as I am aware this is not possible with <Play>. When you give Twilio an mp3 file to play it first downloads and caches the file (if the headers allow for it). When working with mp3 files Twilio expects an existing file and a finite file size.
I think using a conference, or a series of direct one to one calls, to play the stream as you suggested is likely the best solution. If you do have millions of minutes per month then I recommend you get in touch with the Twilio sales team who might be able to make those minutes more affordable.
My iOS app uses AVPlayer to decode H.264 videos with AAC audio tracks out of local device storage. Content with bit rate spikes cause audio to drop shortly (less than a second) after the spike is played, yet video playback continues normally. Playing the videos through Safari seems to work fine, and this behavior is repeatable on several models of iPhones ranging from 6s through 8 plus.
I've been looking for any messages generated, delegates called with error information, or interesting KVOs, but there's been no helpful information so far. What might I do to get some sort of more detailed information that can point me in the right direction?
Turned out that the AVPlayer was configured to utilize methods for loading data in a custom way. The implementation of these methods failed to follow the pattern of satisfying the requests completely. (Apple docs are a vague about this.) The video portion of the AVPlayer asked for more data repeatedly, so eventually all its data got pulled. However, the audio portion patiently waited for the data to come in because there were neither an error state reported nor was all the data provided -- the presumption being that it was pending.
So, in short, sounds like there's provisions in the video handling code to treat missing data as a stall of some form and to plow onward, whereas audio doesn't have that feature. Not a bad design -- if audio cuts out it's very noticeable, and it's also by far the smaller stream so it's much less likely.
Despite spending quite a few days on the problem before posting, the lack of any useful signals made it hard to chase down the problem. I eventually reasoned that if there's no error in producing output from the stream, the problem must be in the delivery of the stream, and the problem revealed itself once I started tweaking the data loading code.
I've got an app that currently ships with all the videos it can play embedded in it. This doesn't scale well, and unless you want to play all the movies, wastes disk space. It also makes it less desirable to upgrade the app because you have to re-download all movies.
What I would like to do is download the movie on the fly, play it back while downloading, and then if it's successfully downloaded, save it to the file system so that next time they want to watch it, it streams from the local file.
I can do whatever is needed to the video, but currently I'm serving it up as an .mp4 file from Amazon S3, with a mimetype of video/mp4, and so the first half of my issue works fine: the movie downloads, and MPMovieViewController will start playing it as soon as it thinks it has downloaded "enough."
Is there any way to tap into the cache of that video file so that I can save it and control how long it resides on the filesystem? This seems like it would be the easiest approach.
I am targeting iOS 5+6, but if the only solution available required iOS 6, I would consider it also. Thanks!
UPDATE: Using AFNetworking, I am now half-way there, I think. I am downloading the video file from the server, and listening for the download progress. Once I see 25% of the video has been downloaded, I start playback on the local file using an MPMoviePlayerController.
The main issue I'm running into now is playback seems to get screwed up. It's going along fine, 25% downloaded, playback starts... download continues normally... then the file finishes downloading completely, and shortly thereafter video freezes. The onscreen playback timer still indicates playback is ongoing and I don't see any "playback finished" type notifications, but the video is frozen. My guess based on the behavior is that perhaps the initial buffer for the video playback was used up, and it isn't detecting that more video is available on disk now?
Is there any way to interact with MPMoviePlayerController to let it know periodically to refresh the buffer it's playing out of? Or some other way to handle this situation?
UPDATE: Make sure to see the newer answer from #TomHamming.
I have yet to find a conclusive answer, but at this time I believe the answer is: you can't reliably do this. At least not without a lot of work which seems too much like a hack. I filed a feature request with Apple as it really seems like this should be possible with some adjustments to MPMoviePlayerController.
I will go over the variety of things I tried or considered, and the results I encountered.
Pass MPMoviePlayerController a URL to your movie file, which allows it to stream, and then pull the file out of the cache it was saved into, into your local Documents folder. Won't work, as of iOS 6. I filed a feature request with Apple, but as it stands now there's no way to get your hands on the file they are downloading, AFAIK.
Start downloading the movie file with NSURLConnection (or something like AFNetwork), and then when a "decent amount" has been downloaded to the device, pass the file URL to the MPMoviePlayerController and let it stream from disk. Sort of works, but not well. Three problems:
It's really hard to know when to start playing the file. I haven't figured out the algorithm Apple uses, and so I always erred on the side of caution, waiting for 25% to be downloaded before playing.
The MPMoviePlayerController interface provides no sense of the movie being streamed, as it does when Apple is doing the calculations via the network. It appears to the user that the file is totally downloaded when it really is not.
And most importantly, MPMoviePlayerController seems to not work well with playing a file that is not completely downloaded. I experienced playback problems once the file finished downloading, or if the player caught up with the amount downloaded, and never found a graceful way to handle these situations.
Same procedure as above, but use AVFoundation classes to more finely control the playback process, and avoid the issues described above regarding playback stopping, etc. Might work, but I want all the features of MPMoviePlayerController. Re-implementing MPMoviePlayerController myself just to get this one feature seems like a waste of time.
Same procedure as #1 above, but run a small web server in your app to handle streaming the video from the disk to MPMoviePlayerController, with the hope being that the streaming would work more like it normally does when streaming the file directly from an external web server. Works, but results were still sporadic and performance seemed to suffer. I did my test with CocoaHTTP. I decided against this approach because it just felt like a terrible hack.
Run a lightweight HTTP proxy, thus intercepting the downloaded movie file data as it gets streamed from the internet into your MPMoviePlayerController. Not sure if this works or not. I was not able to test this yet, as I have not found a lightweight HTTP proxy written in Objective-C, and at this point don't feel like implementing one just to try this experiment. It seems like the next easiest of all these hacks to implement -- if you don't have to write the proxy!
At this point I've decided to go the less-hacky, but also less user-friendly route of simply downloading the file completely, and then passing it to MPMoviePlayerController, until a better solution comes along.
You can do this as of iOS 10 with AVAssetDownloadTask. See this WWDC 2016 session and this documentation.
Alternatively, if your movie isn't DRM'd, you can do it with AVAssetResourceLoaderDelegate, which effectively lets you give an AVPlayer an arbitrary stream of bytes. See this walkthrough.
i'm writing an app to play some media encrypted files
Normally,we can decrypt these files and play it.But i don't want anybody can get this decrypt file when app is playing this file.
Or i want protect these file.
I'm researching but i don't find a solution.
Can anyone suggest to me a solution?Can anyway to protect media files without encryption?
Thanks so much.
Regards
The short answer: You can't stop copying, no matter how hard you try.
The long answer: This problem has been around since the dawn of Internet distribution. Nobody has solved it effectively yet. The problem is that if a user jailbreaks a device they can do anything that the hardware is capable of. This includes recording directly from the audio buffer into a file, making it a simple process to capture your file while it is playing and dump the contents into another file. Therefore, if you can play it, you can copy it. The only solution that I can see working is to build your own hardware that doesn't allow external access to the audio buffer, but that is impossible for 99% of people and impractical for 100%.
The compromise: The best you can do is make it more trouble than it is worth for the user. If you can decrypt into a memory buffer then it will be an annoying task to get the data, and most people will probably not put the effort into it.
My app needs to encode a large amount of audio data to an M4A file. I am currently using AVAssetWriter, which works fine, except that it takes a few minutes to encode all the data.
Instead of asking the user to keep the app running until the process has finished, I would like to pause the encoding when the app terminates and continue on relaunch.
Unfortunately, AVAssetWriter doesn't seem to support this, as it always creates a new file when initializing.
Do you know any other APIs that I could use? Maybe a third-party library?
This is exactly what background processing is intended for. As long as you can complete within 10 minutes, you can use beginBackgroundTaskWithExpirationHandler: to ask the system to let you keep running after the user switches applications. See Completing a Finite-Length Task in the Background in the iOS Application Programming Guide. Not only is this the easiest to use, but it'll give the best user experience.
The only issue you'd face is if it's possible for an audio file to take longer than 10 minutes in a non-resumable way. If that's a real possibility, then you'll need another solution.