I'm trying to play some mp3 files (which app downloaded from the remote server) from sd card using Cordova.
I tried to use following:
if($ionicPlatform.is('android')){
src = 'yourPersistantAppFolder/main_expansion/' + src;
}
and
if($ionicPlatform.is('android')){
src = 'sdcard/yourPersistantAppFolder/main_expansion/' + src;
}
But without luck.
I tried to find some anwser here:
https://github.com/apache/cordova-plugin-file
But without the luck.
Many thanks for any advice.
Edit:
Path in Android is displayed like this:
This may help:
(jc??? are mysupport routines)
import { File } from "#ionic-native/file";
import { Diagnostic } from "#ionic-native/diagnostic";
constructor(
...
public file: File,
public diagnostic: Diagnostic
){
this.diagnostic.getExternalSdCardDetails()
.then( (data) => {
this.jcError += "\n" + "sd:" + JSON.stringify( data);
this.jcError += "\n" + "Number cards: " + data.length;
for( let ii = 0; ii < data.length; ii += 1){
let thisElem = data[ii];
if( thisElem.type.toLowerCase() === "application" && thisElem.canWrite){
this.ourSDentry = thisElem;
basePathSD = thisElem.filePath;
break;
}
}
if( !basePathSD){
this.jcError += "\n\n" + "no SD card found";
return;
}
}, (errData)=>{
tag = "getExternalSdCardDetails";
this.jcError += "\n\n" + tag + ":ERR:" + JSON.stringify( errData);
});
Related
I'm trying to build Chromium Android with h264 support in webrtc. My understanding is that the following args.gn file should do what I want.
target_os = "android"
target_cpu = "arm64"
proprietary_codecs = true
ffmpeg_branding = "Chrome"
However, when I install the APK on my Pixel 3, use chrome://inspect to debug from my desktop and run new RTCPeerConnection().createOffer({offerToReceiveVideo: true}).then(s => console.log(s.sdp)) I only see VP8 and VP9 codecs.
Is there anything else I'm missing?
I ended up having to change the code to get the behavior I wanted.
Setting these build flags causes the GPU process to answer, "Yes, I support H264 video decoding" to any queries https://cs.chromium.org/chromium/src/media/gpu/android/media_codec_video_decoder.cc?q=proprietary_codecs&sq=package:chromium&dr=C&l=154
However, webrtc's definition of supported codecs comes from this function which is simply polling the formats supported by the encoder. https://webrtc.googlesource.com/src/+/refs/heads/master/media/engine/webrtc_video_engine.cc#142. So it appears that although my Pixel 3 supports H264 decoding it doesn't support encoding and so webrtc considers it an unsupported format. Interestingly, Chrome running on the exact same device does support webrtc H264.
I'm only looking to receive H264 video so I edited this function to add a webrtc::SdpVideoFormat for each H264 format that Chrome supports.
+static void AddH264Formats(std::vector<webrtc::SdpVideoFormat>& formats) {
+ webrtc::SdpVideoFormat h264Format(kH264CodecName, {
+ {cricket::kH264FmtpLevelAsymmetryAllowed, "1"}});
+
+ h264Format.parameters[cricket::kH264FmtpProfileLevelId] = "42001f";
+ h264Format.parameters[cricket::kH264FmtpPacketizationMode] = "1";
+ if(std::find(formats.begin(), formats.end(), h264Format) == formats.end()) {
+ formats.push_back(h264Format);
+ }
+ h264Format.parameters[cricket::kH264FmtpPacketizationMode] = "0";
+ if(std::find(formats.begin(), formats.end(), h264Format) == formats.end()) {
+ formats.push_back(h264Format);
+ }
+
+ h264Format.parameters[cricket::kH264FmtpProfileLevelId] = "42e01f";
+ h264Format.parameters[cricket::kH264FmtpPacketizationMode] = "1";
+ if(std::find(formats.begin(), formats.end(), h264Format) == formats.end()) {
+ formats.push_back(h264Format);
+ }
+ h264Format.parameters[cricket::kH264FmtpPacketizationMode] = "0";
+ if(std::find(formats.begin(), formats.end(), h264Format) == formats.end()) {
+ formats.push_back(h264Format);
+ }
+
+ h264Format.parameters[cricket::kH264FmtpProfileLevelId] = "4d0032";
+ h264Format.parameters[cricket::kH264FmtpPacketizationMode] = "1";
+ if(std::find(formats.begin(), formats.end(), h264Format) == formats.end()) {
+ formats.push_back(h264Format);
+ }
+ h264Format.parameters[cricket::kH264FmtpPacketizationMode] = "0";
+ if(std::find(formats.begin(), formats.end(), h264Format) == formats.end()) {
+ formats.push_back(h264Format);
+ }
+}
+
std::vector<VideoCodec> AssignPayloadTypesAndDefaultCodecs(
const webrtc::VideoEncoderFactory* encoder_factory) {
- return encoder_factory ? AssignPayloadTypesAndDefaultCodecs(
- encoder_factory->GetSupportedFormats())
- : std::vector<VideoCodec>();
+ auto formats = encoder_factory->GetSupportedFormats();
+ AddH264Formats(formats);
+
+ return AssignPayloadTypesAndDefaultCodecs(formats);
}
Instead of editing the webrtc code I think I may edit GpuVideoAcceleratorFactoriesImpl::GetVideoEncodeAcceleratorSupportedProfiles. Editing the GpuVideoAcceleratorFactoriesImpl this way may be less correct but it would allow me to fork Chromium without having to mess with third_party repositories.
I've got simple app, and it works fine on my PC. But on my Android-Testing Device it can not work properly. Something wrong with the paths. For Android I'm using the code to get files I want to read/write from StreamingAssets to Application.persistentDataPath:
void Awake(){if (firstWord == "Adroid" || deviceType == "Handheld")
{
StartCoroutine("Downloader");
}
}
IEnumerator Downloader()
{
WWW wwwDD = new WWW("jar:file://" + Application.dataPath + "!/assets/DropDown.xml");
yield return wwwDD;
if (wwwDD.isDone == true)
{
File.WriteAllBytes(Application.persistentDataPath + "/DropDown.xml", wwwDD.bytes);
}
WWW www1st = new WWW("jar:file://" + Application.dataPath + "!/assets/1st.xml");
yield return www1st;
if (www1st.isDone == true)
{
File.WriteAllBytes(Application.persistentDataPath + "/1st.xml", www1st.bytes);
}
WWW wwwDefault = new WWW("jar:file://" + Application.dataPath + "!/assets/Default.xml");
yield return wwwDefault;
if (wwwDefault.isDone == true)
{
File.WriteAllBytes(Application.persistentDataPath + "/Default.xml", wwwDefault.bytes);
}
}
And in logcat I've got error:
UnauthorizedAccessException: Access to the path '/data/data/<my project>/files/' is denied.
Write Access is set to Internal, and if I change it to External and add to AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I get the same problem.
What am I doing wrong? Please tell me, I haven't sleep for about a week trying to solve this
I wrote some code to get all the folders inside a folder inside the StreamingAssets and then to get all the files in that folder.
It works well on Windows but I can't get it to work on Android.
Here is the code :
foreach (string s in Directory.GetDirectories(model.path + "/Levels")) {
GameObject el = (GameObject)Instantiate(listButton, Vector3.zero, Quaternion.identity);
el.transform.SetParent(grid1.transform);
string[] words = s.Split('/');
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
words = s.Split('\\');
#endif
el.GetComponentInChildren<Text>().text = words[words.Length - 1];
el.GetComponent<Button>().onClick.AddListener(() => {
MapSizeButtonClick(Int32.Parse(el.GetComponentInChildren<Text>().text));
});
}
I had to add the #if UNITY_STANDALONE_WIN for windows because of the '\'.
Then for the files inside that folder I wrote this :
foreach (string s in Directory.GetFiles(model.path + "/Levels/" + model.mapSize + "/" + model.colorNumber)) {
string[] words = s.Split('/');
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
words = s.Split('\\');
#endif
words = words[words.Length - 1].Split('.');
if (words[1] == "json") {
GameObject el = (GameObject)Instantiate(listButton, Vector3.zero, Quaternion.identity);
el.transform.SetParent(grid3.transform);
el.GetComponentInChildren<Text>().text = words[0];
el.GetComponent<Button>().onClick.AddListener(() => {
levelButtonClick(Int32.Parse(el.GetComponentInChildren<Text>().text));
});
}
}
I'm using UnityEngine.UI.Directory but I read that it can't be use on Android and I must use WWW instead. Something like this :
string xmlSetUpPath = "jar:file://" + Application.dataPath + "!/assets/xml/xmlSetUp.xml";
WWW book1WWW = new WWW(book1Path);
yield return book1WWW;
if(!File.Exists(Application.persistentDataPath + "/xml/book1.xml"))
{
File.WriteAllBytes(Application.persistentDataPath + "/xml/book1.xml", book1WWW.bytes);
}
However I couldn't find anything like Directory.getFiles() or Directory.getFolder(). So I thought I could use WWW to check if the file exists (as the file names are 1.json, 2.json, 3.json) and iterate until a file doesn't exist.
But I would also need to check if a folder exists for the 1st part of the script and I can't find how to check if a folder exists with WWW. (My folders names are also 1,2,3,4...)
So how to check if a folder exists with WWW ?
Or what else can I do ?
UPDATE :
I updated the code, now it looks like this :
for (int i = 0; i < 100; i++) {
if (Directory.Exists(Path.Combine(model.path, "Levels/" + i.ToString()))){
GameObject el = (GameObject)Instantiate(listButton, Vector3.zero, Quaternion.identity);
el.transform.SetParent(grid1.transform);
el.GetComponentInChildren<Text>().text = i.ToString();
el.GetComponent<Button>().onClick.AddListener(() => {
MapSizeButtonClick(Int32.Parse(el.GetComponentInChildren<Text>().text));
});
}
}
I use path.combine() and check every folder from 0 to 100. It works on Windows but it still doesn't work in Android.
The path is set like this :
#if UNITY_IPHONE
path = Application.dataPath + "/Raw";
#endif
#if UNITY_ANDROID
path = "jar:file://" + Application.dataPath + "!/assets";
#endif
#if UNITY_STANDALONE || UNITY_EDITOR
path = Application.dataPath + "/StreamingAssets";
#endif
QUESTION UPDATE
I made a script that generate the file paths. The paths are always the same : "FolderNumerotedFromYToX/FolderNumerotedFromYToX/FileNumerotedFrom1ToX.json". The generation works but the writing to JSON doesn't. It outputs "{}".
// Generate level list
List<KeyValuePair<int, List<KeyValuePair<int, List<int>>>>> l;
l = new List<KeyValuePair<int, List<KeyValuePair<int, List<int>>>>>();
for (int i = 1; i < 100; i++) {
if (Directory.Exists(Path.Combine(Path.Combine(Application.dataPath, "StreamingAssets"), "Levels/" + i.ToString()))) {
l.Add(new KeyValuePair<int, List<KeyValuePair<int, List<int>>>>(i, new List<KeyValuePair<int, List<int>>>()));
for (int j = 1; j < 100; j++) {
if (Directory.Exists(Path.Combine(Path.Combine(Application.dataPath, "StreamingAssets"), "Levels/" + i + "/" + j))) {
l[l.Count - 1].Value.Add(new KeyValuePair<int, List<int>>(j, new List<int>()));
int k = 1;
while (true) {
if (File.Exists(Path.Combine(Path.Combine(Application.dataPath, "StreamingAssets"), "Levels/" + i + "/" + j + "/" + k + ".json"))) {
l[l.Count - 1].Value[l[l.Count - 1].Value.Count - 1].Value.Add(k);
}
else
break;
k++;
}
}
}
}
}
string ljson = JsonUtility.ToJson(l);
var lsr = File.CreateText("Assets/StreamingAssets/levels.json");
lsr.WriteLine(ljson);
lsr.Close();
Can you help me finding a way to store this to a file ?
It may sound hard, but you really have to use the WWW class to access your files from StreamingAssets on Android.
And you have to keep a list of your filenames, to be able to access them, as there seems to be no way to use something like File.Exists or Directory.GetFiles.
Example:
WWW www = new WWW(source);
yield return www;
if (string.IsNullOrEmpty(www.error))
{
// make sure the destination directory exists
File.WriteAllBytes(destination, www.bytes);
}
else
{
// error handling
}
Your source files (base) path should look like this:
jar:file://" + Application.dataPath + "!/assets/
From the docs:
Note that on Android, the files are contained within a compressed .jar
file (which is essentially the same format as standard zip-compressed
files). This means that if you do not use Unity’s WWW class to
retrieve the file then you will need to use additional software to see
inside the .jar archive and obtain the file.
Source: http://docs.unity3d.com/Manual/StreamingAssets.html
To solve this problem I created pre-compilation script which will run before the compilation; this script will list the names of the files you want to access later in text file
#if UNITY_EDITOR
using UnityEditor.Build;
using UnityEditor;
using System.IO;
public class BM_AndroidBuildPrepartion : IPreprocessBuild
{
public int callbackOrder { get { return 0; } }
public void OnPreprocessBuild(BuildTarget target, string path)
{
// Do the preprocessing here
string[] fileEntries = Directory.GetFiles("Assets/Resources/Prefabs/alphabet", "*.prefab");
System.IO.Directory.CreateDirectory("Assets/StreamingAssets/");
using (StreamWriter sw = new StreamWriter("Assets/StreamingAssets/alphabet.txt", false))
{
foreach (string filename in fileEntries) {
sw.WriteLine(Path.GetFileNameWithoutExtension(filename));
}
}
}
}
#endif
then I read the text file and you can access the files in same way but you have to put them inside your project in Assets/StreamingAssets/
#if UNITY_ANDROID
string path = "jar:file://" + Application.dataPath + "!/assets/alphabet.txt";
WWW wwwfile = new WWW(path);
while (!wwwfile.isDone) { }
var filepath = string.Format("{0}/{1}", Application.persistentDataPath, "alphabet.t");
File.WriteAllBytes(filepath, wwwfile.bytes);
StreamReader wr = new StreamReader(filepath);
string line;
while ((line = wr.ReadLine()) != null)
{
//your code
}
#endif
Error in checking the file.
I have use one code. But i think there is some problem. The file got stuck to one file. And always keep dowloading the same file.
here is how i code this. Here in the below code. I am trying to download the images to local sdcard. If the file is already available i dont want it to download. And if not, then download. But it seems its just keep repeat download the same file.
function appReady(datadira){
$(".gallery").html("Ready to check remote files...");
$.get("http://www.pankhida.com/main/?json=get_page&page_id=115&callback=?", {}, function(res) {
if (res.page.attachments.length > 0) {
$(".gallery").html("Going to sync some images...");
for (var i = 0; i < res.page.attachments.length; i++) {
if (knownfiles.indexOf(res.page.attachments[i].url) == -1) {
//alert("need to download " + res[i]);
var ft = new FileTransfer();
var fullPath = res.page.attachments[i].url;
var filename = fullPath.replace(/^.*[\\\/]/, '');
var dlPath = DATADIR.toURL() + "/" + filename;
var uri= res.page.attachments[i].url;
uri = encodeURI(uri);
//console.log("downloading crap to " + dlPath);
window.resolveLocalFileSystemURL(DATADIR.toURL() +"/"+ filename, appStart, function(){
ft.download(uri, dlPath, function(e){
//renderPicture(e.toURL());
alert("Successful download of "+e.toURL());
}, onError, true);
});
}
}
}
$(".gallery").html("");
}, "json");
}
I am using window.resolveLocalFileSystemURL which i got from this URL http://www.raymondcamden.com/2014/7/1/Cordova-Sample-Check-for-a-file-and-download-if-it-isnt-there.
Please suggest where i am wrong. Or any correct code will be really helpful.
It has to do with the closure inside resolveLocalFileSystemURL.The value of ft ends up being the last one used from the loop. Try changing
for (var i = 0; i < res.page.attachments.length; i++) {
to
res.page.attachments.forEach(function(attachment) {
and the last } to }).
Inside the loop, use attachment instead of res.page.attachments[i].
Here I am using .CSV file in phonegap application for one application.
I have 25 .CSV files.
I want to get full all 25 .CSVs in my application.
I tried this link
for my reference but it takes from input.
i dont want to get file from user input. i want to get file directly from www folder.
$(document).ready(function () {
if (isAPIAvailable()) {
$('#files').bind('change', handleFileSelect);
}
});
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
//var files = new array['C:\Users\Bhavdip Bhalodia\Desktop\raw\bc.csv'];
var file = "C:\Users\Bhavdip Bhalodia\Desktop\raw\bc.csv";
alert("file" + file);
// read the file metadata
var output = ''
output += '<span style="font-weight:bold;">' + escape(file.name) + '</span><br />\n';
output += ' - FileType: ' + (file.type || 'n/a') + '<br />\n';
output += ' - FileSize: ' + file.size + ' bytes<br />\n';
output += ' - LastModified: ' + (file.lastModifiedDate ? file.lastModifiedDate.toLocaleDateString() : 'n/a') + '<br />\n';
// read the file contents
printTable(file);
// post the results
$('#list').append(output);
}
function printTable(file) {
var reader = new FileReader();
reader.readAsText(file);
reader.onload = function (event) {
var csv = event.target.result;
var data = $.csv.toArrays(csv);
var html = '';
for (var row in data) {
html += '<tr>\r\n';
for (var item in data[row]) {
html += '<td>' + data[row][item] + '</td>\r\n';
}
html += '</tr>\r\n';
}
$('#contents').html(html);
};
reader.onerror = function () {
alert('Unable to read ' + file.fileName);
};
}
UPDATE
I dont want to read CSV manual change we want to take file from the path. without user prompting input.
In this example, input taking from user but i dont want.
I went here also:
Thanks and sorry for my Grammar.
If the file is under the www folder of your app You should just be able to load the contents using an "AJAX" fetch even though it is bundled in the app.
$.get('js/filename.ext');