{ "id": "120667", "key": "TIMOB-15468", "fields": { "issuetype": { "id": "2", "description": "A new feature of the product, which has yet to be developed.", "name": "New Feature", "subtask": false }, "project": { "id": "10153", "key": "TIMOB", "name": "Titanium SDK/CLI", "projectCategory": { "id": "10100", "description": "Titanium and related SDKs used in application development", "name": "Client" } }, "fixVersions": [], "resolution": { "id": "1", "description": "A fix for this issue is checked into the tree and tested.", "name": "Fixed" }, "resolutiondate": "2015-06-01T21:46:09.000+0000", "created": "2013-10-01T15:05:27.000+0000", "priority": { "name": "Critical", "id": "1" }, "labels": [ "AudioPlayer", "TSP", "error", "event" ], "versions": [], "issuelinks": [], "assignee": { "name": "emerriman", "key": "emerriman", "displayName": "Eric Merriman ", "active": true, "timeZone": "America/Los_Angeles" }, "updated": "2017-03-21T21:01:46.000+0000", "status": { "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.", "name": "Closed", "id": "6", "statusCategory": { "id": 3, "key": "done", "colorName": "green", "name": "Done" } }, "components": [ { "id": "10224", "name": "TiAPI", "description": "This component is used for cross-platform API work. Specifications are most likely to use this component." } ], "description": "Titanium.Media.AudioPlayer really needs a proper error event. 'Change' and 'progress' aren't enough. \r\n\r\n\r\nCurrently, if a stream is broken, or (as is often the case) has the wrong buffer size set (as can be demonstrated in the KitchenSink remote streaming example) we only forced the same alert \"Unable to configure network read stream\". \r\n\r\n\r\nThis error info isn't very useful. Debug logs shows more info logged by AudioStreamer.m which provides more info eg : \"Audio packets are larger than kAQBufSize.\"\r\n\r\n\r\n\r\n\r\n\r\n", "attachment": [], "flagged": false, "summary": "iOS: Titanium.Media.AudioPlayer needs an error event", "creator": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "subtasks": [], "reporter": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "environment": "iOS", "closedSprints": [ { "id": 407, "state": "closed", "name": "2015 Sprint 11 SDK", "startDate": "2015-05-23T00:00:08.253Z", "endDate": "2015-06-06T00:00:00.000Z", "completeDate": "2015-06-08T16:18:16.381Z", "originBoardId": 114 } ], "comment": { "comments": [ { "id": "336011", "author": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "body": "Still no activity on this. \r\n\r\nIf a stream fails to start() the \"File Error: Unable to configure network read stream\" alert pops up and there's no way get rid of that, or catch anything to provide a better message/retry. \r\n\r\n", "updateAuthor": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "created": "2014-12-11T16:30:23.000+0000", "updated": "2014-12-11T16:30:23.000+0000" }, { "id": "337142", "author": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "body": "This looks to be a simple fix on iOS.\r\n\r\nThe AudioStreamerCUR.m file has a failWithErrorCode method which is throwing up the error alert. \r\n\r\nThis just needs to be fired back in an error event. \r\n\r\n", "updateAuthor": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "created": "2014-12-19T10:57:56.000+0000", "updated": "2014-12-19T10:57:56.000+0000" }, { "id": "337146", "author": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "body": "In fact, there is still a silly amount of disparity between iOS and Android, when it comes to the AudioPlayer. \r\n\r\nState codes differ. \r\niOS has no setTime() ability. \r\nAndroid seems to only fire the 'complete' event.\r\netc.\r\n\r\nI'm sure these were previously addressed a while ago. ", "updateAuthor": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "created": "2014-12-19T13:07:37.000+0000", "updated": "2014-12-19T13:09:07.000+0000" }, { "id": "339223", "author": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "body": "It would also be very useful to detect when the audioPlayer (for example, playing a radio stream in the background) is 'interrupted' by things like an Alarm (or any other audio notification), audio in another app 'stealing' the session, Siri, etc. - Currently, after the audio is interrupted, it does not recover afterwards. \r\n\r\nI have used a module which uses CoreTelephony to detect when the stream is interrupted (app paused) by a phone call and have been able to stop/resume my stream when that occurs. ", "updateAuthor": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "created": "2015-01-15T12:17:08.000+0000", "updated": "2015-01-15T12:17:08.000+0000" }, { "id": "344014", "author": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "body": "More on this: \r\n\r\nI see that the original AudioStreamer implementation by Steve Tramer was a modification of some popular code by Matt Gallagher. \r\n\r\nRecently, while looking for a solution to obtaining now-playing metadata from ShoutCast stream, I've come across another modified version of the AudioStreamer classes which will detect and read the 'Icy-Metadata' if present. \r\n\r\nIt would be great to add this patch to our AudioPlayer if possible. \r\n\r\nhttps://code.google.com/p/audiostreamer-meta/\r\n\r\nThis solution is based on an article here, which explains how metadata is streamed by ShoutCast. http://www.smackfu.com/stuff/programming/shoutcast.html\r\n\r\n\r\nThanks.\r\n\r\n\r\n\r\n", "updateAuthor": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "created": "2015-02-20T15:00:27.000+0000", "updated": "2015-02-20T15:00:27.000+0000" }, { "id": "344015", "author": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "body": "update : There is a much, much more recent fork of the AudioStreamer classes here, which has built-in support for Shoutcast metadata, ID3 tags, seeking and also playlists (Ti devs often use the Media.videoPlayer for playlists .m3u etc.) \r\n\r\nhttps://github.com/alexcrichton/AudioStreamer/tree/master/AudioStreamer\r\n\r\nPlease can we have a solution based around this? It would be a huge, huge improvement to the very old methods we currently have. \r\n", "updateAuthor": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "created": "2015-02-20T15:32:58.000+0000", "updated": "2015-02-20T15:38:36.000+0000" }, { "id": "344019", "author": { "name": "ingo", "key": "ingo", "displayName": "Ingo Muschenetz", "active": true, "timeZone": "America/Los_Angeles" }, "body": "If someone is willing/able to contribute a solution to this, we would be glad to assist.", "updateAuthor": { "name": "ingo", "key": "ingo", "displayName": "Ingo Muschenetz", "active": true, "timeZone": "America/Los_Angeles" }, "created": "2015-02-20T15:44:45.000+0000", "updated": "2015-02-20T15:44:45.000+0000" }, { "id": "344020", "author": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "body": "If I knew how to do it, I would (I'm an extreme novice when it comes to Objective-C) ;) \r\n\r\nI've done the research bit ;) ", "updateAuthor": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "created": "2015-02-20T15:47:44.000+0000", "updated": "2015-02-20T15:47:44.000+0000" }, { "id": "349453", "author": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "body": "Hi,\r\n\r\nI seen the status of this update a few times recently. \r\nIs there a rough ETA of when this might be fixed? \r\n\r\nI have a radio station app to get updated which really needs this as soon as possible. \r\nThanks.\r\n\r\n", "updateAuthor": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "created": "2015-04-14T14:07:42.000+0000", "updated": "2015-04-14T14:07:42.000+0000" }, { "id": "353743", "author": { "name": "cng", "key": "cng", "displayName": "Chee Kiat Ng", "active": false, "timeZone": "America/Los_Angeles" }, "body": "PR here: https://github.com/appcelerator/titanium_mobile/pull/6879\r\nAdded iOS error event, as well as documented together with Android.\r\nAlso removed alert dialog that shows generic error. Users are now required to process the returned error event.\r\n\r\nh4. Sample Code (same as documentation, but added error event listener)\r\n{code}\r\nvar win = Titanium.UI.createWindow({ \r\n title:'Audio Test',\r\n backgroundColor:'#fff',\r\n layout: 'vertical'\r\n});\r\n\r\nvar startStopButton = Titanium.UI.createButton({\r\n title:'Start/Stop Streaming',\r\n top:10,\r\n width:200,\r\n height:40\r\n});\r\n\r\nvar pauseResumeButton = Titanium.UI.createButton({\r\n title:'Pause/Resume Streaming',\r\n top:10,\r\n width:200,\r\n height:40,\r\n enabled:false\r\n});\r\n\r\nwin.add(startStopButton);\r\nwin.add(pauseResumeButton);\r\n\r\n// allowBackground: true on Android allows the \r\n// player to keep playing when the app is in the \r\n// background.\r\nvar audioPlayer = Ti.Media.createAudioPlayer({ \r\n url: 'http://www.tonycuffe.com/mp3/girlwho_lo.mp3',\r\n allowBackground: true\r\n}); \r\n\r\nstartStopButton.addEventListener('click',function() {\r\n // When paused, playing returns false.\r\n // If both are false, playback is stopped.\r\n if (audioPlayer.playing || audioPlayer.paused)\r\n {\r\n audioPlayer.stop();\r\n pauseResumeButton.enabled = false;\r\n if (Ti.Platform.name === 'android')\r\n { \r\n audioPlayer.release();\r\n } \r\n }\r\n else\r\n {\r\n audioPlayer.start();\r\n pauseResumeButton.enabled = true;\r\n }\r\n});\r\n\r\npauseResumeButton.addEventListener('click', function() {\r\n if (audioPlayer.paused) {\r\n audioPlayer.start();\r\n }\r\n else {\r\n audioPlayer.pause();\r\n }\r\n});\r\n\r\naudioPlayer.addEventListener('progress',function(e) {\r\n Ti.API.info('Time Played: ' + Math.round(e.progress) + ' milliseconds');\r\n});\r\n\r\naudioPlayer.addEventListener('change',function(e)\r\n{\r\n Ti.API.info('State: ' + e.description + ' (' + e.state + ')');\r\n});\r\n\r\naudioPlayer.addEventListener('error',function(e)\r\n{\r\n Ti.API.info('error: ' + e.error + ' (' + e.code + ')');\r\n});\r\n\r\nwin.addEventListener('close',function() {\r\n audioPlayer.stop();\r\n if (Ti.Platform.osname === 'android')\r\n { \r\n audioPlayer.release();\r\n }\r\n});\r\n\r\nwin.open();\r\n{code}\r\n\r\nh4. Steps to test\r\n1. Run sample app while online\r\n2. *Start / Stop Streaming*\r\n3. While music is playing, go offline\r\n\r\nh4. Expected result\r\nthe error event should be caught, and console prints out error description", "updateAuthor": { "name": "cng", "key": "cng", "displayName": "Chee Kiat Ng", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2015-05-28T04:14:05.000+0000", "updated": "2015-05-28T04:14:05.000+0000" }, { "id": "353770", "author": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "body": "+1 Thanks! I'll try this out. ", "updateAuthor": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "created": "2015-05-28T10:59:26.000+0000", "updated": "2015-05-28T10:59:26.000+0000" }, { "id": "353883", "author": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "body": "Hi, \r\n\r\nThis worked for me. Also including Pedro's extra fixes since your PR. Thank you! \r\n\r\nBUT one more thing which just occurred to me also, is the fact that the iOS version of AudioPlayer does not have a 'complete' event. \r\n\r\nAndroid does have this event. \r\n\r\nThe 'complete' event should fire when the player reaches the end of a file. \r\n\r\nCould this also be added? For the sake of parity. Thank you. ", "updateAuthor": { "name": "kosso", "key": "kosso", "displayName": "kosso", "active": true, "timeZone": "Europe/London" }, "created": "2015-05-29T13:31:29.000+0000", "updated": "2015-05-29T13:31:29.000+0000" }, { "id": "354029", "author": { "name": "penrique", "key": "penrique", "displayName": "Pedro Enrique", "active": false, "timeZone": "America/Los_Angeles" }, "updateAuthor": { "name": "penrique", "key": "penrique", "displayName": "Pedro Enrique", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2015-06-01T21:48:29.000+0000", "updated": "2015-06-01T21:48:29.000+0000" }, { "id": "414402", "author": { "name": "lmorris", "key": "lmorris", "displayName": "Lee Morris", "active": false, "timeZone": "America/Los_Angeles" }, "body": "Closing ticket as fixed.", "updateAuthor": { "name": "lmorris", "key": "lmorris", "displayName": "Lee Morris", "active": false, "timeZone": "America/Los_Angeles" }, "created": "2017-03-21T21:01:46.000+0000", "updated": "2017-03-21T21:01:46.000+0000" } ], "maxResults": 16, "total": 16, "startAt": 0 } } }