Playback Widevine with token from Azure Media Services - react-native

Good morning everyone,
I'm having a hard time trying to add a simple Authorization token to playback widevine protected content from azure media services using react-native-video.
here is my code :
ref={(ref: Video) => { this.video = ref }}
source={{
uri: "https://swannmediaservice-euwe.streaming.media.azure.net/95aae6ef-55a4-411d-9706-73890f5d2ba5/L'Homme qui courait après le Te.ism/manifest(format=mpd-time-cmaf,encryption=cenc)",type: 'mpd',
drm: {
type: 'widevine',
headers: {
'Authorization': 'Bearer=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3d3dy5zYXRvcmlwb3AuY29tLyIsImF1ZCI6InVybjpzYXRvcmlwb3AiLCJleHAiOjE3MTA4MDczODksIm5iZiI6MTYwMTMwMDA3OH0.O_41HbAcE8kFDivOM9Q4AL2z-4TMUTLchuUoyxCdDKY'
}
}
}}
this ofc is just for testing purposes.
This always gives me this error in the log output when i test it on Android :
Caused by: java.lang.IllegalStateException: Media requires a DrmSessionManager
Which I'm assuming is due to the video not being able to play.
I tested this in the azure media player and everything works correctly.
here is a link for that :
https://aka.ms/azuremediaplayer?url=https%3A%2F%2Fswannmediaservice-euwe.streaming.media.azure.net%2F057936a3-2899-4d63-b287-3c50976c1bc4%2FFrench%20audiobook%20The%20Caliph%20A2x_.ism%2Fmanifest(format%3Dmpd-time-csf%2Cencryption%3Dcenc)&widevine=true&widevinetoken=Bearer%3DeyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3d3dy5zYXRvcmlwb3AuY29tLyIsImF1ZCI6InVybjpzYXRvcmlwb3AiLCJleHAiOjE3MTA4MDczODksIm5iZiI6MTYwMTMwMDA3OH0.O_41HbAcE8kFDivOM9Q4AL2z-4TMUTLchuUoyxCdDKY
and it works fine.
is there anything I'm missing here?
Platform
iOS
Android ExoPlayer
Video sample
URI : https://swannmediaservice-euwe.streaming.media.azure.net/95aae6ef-55a4-411d-9706-73890f5d2ba5/L'Homme qui courait après le Te.ism/manifest(format=mpd-time-cmaf,encryption=cenc)
Header: Bearer=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3d3dy5zYXRvcmlwb3AuY29tLyIsImF1ZCI6InVybjpzYXRvcmlwb3AiLCJleHAiOjE3MTA4MDczODksIm5iZiI6MTYwMTMwMDA3OH0.O_41HbAcE8kFDivOM9Q4AL2z-4TMUTLchuUoyxCdDKY

well ,since i figured out my own problem, here is the solution :
Since azure media services consults their own licensing sevice to play media ( and not using a 3d party licensing service ) , exoplayer doesn't realise that and tries to play the video regardless even if there is a licenseServer in the response (manifest settings) or not since it expects a a licenseService pasted in it's DRM settings so it can use it to fetch the license and pass a Header with it.
So basically , when i didn't use a licensServer and thought everything worked automatically , i was wrong.
so what my code was doing , is : it requests a license frorm no where , and it wont work.
So you have to parse the data that is coming from the link , extract the license server manually and add it to the request like this :
ref={(ref: Video) => { this.video = ref }}
source={{
uri: "your mpd url",type: 'mpd',
drm: {
type: 'widevine',
licenseServer: 'the Parsed license server form the mpd file',
headers: {
'Authorization': 'Bearer=yourtoken'
}
}
}}
Implemented that , now everything works great.

May be it comes from the manifest name which may be problematic. I recommend to not use accented characters or special characters like ' as the name is exposed in the the streaming Url. Remove also spaces when possible.
To do so, rename the source file, re-encode the content and give another try.

Related

Cloudinary .mkv format video link is not playing in safari

Hi I am trying to stream the following video on my website from cloudinary, it is playing in all browsers except safari
I have attempted f_auto, q_50, and many other combinations
I have even tried to convert it to mp4
I also noticed that most files above 50MB are doing the same thing
Please help !!!
It is to mention that I am in cloudinary free version.
video link:
https://res.cloudinary.com/impromek-com/video/upload/v1652337443/ucfj0kmirnsmgffrhzyd.mkv
Safari doesn't support MKV's natively so you'd have to convert your video before playback by using a transformation.
Doing that with the video you've provided results in an error In general, to help debug Cloudinary URLs, the response includes an x-cld-error header, and looking at the URL you've shared, I see the header comes back with:
Video is too large to process synchronously, please use an eager transformation with eager_async=true to resolve
There is an online (synchronous) video transformation limit(40MB for free plans and 100 MB for paid ones), which means that for videos larger than the limit you'll need to perform the video transformations eagerly.
Eager transformations can be set upon upload or by updating your current resources using the explicit API.
Please take a look and see if that resolves the issue for you, and if you have any additional questions or need any guidance, just let me know.
Here is a sample code that I used,
const upload = v2.uploader.explicit(
public_id,
{
type: 'upload',
resource_type: 'video',
eager_async: true,
eager: [
{
fetch_format: 'mp4',
},
],
eager_notification_url: your_notification_url,
},
(error, result) => {
if (error) return reject(error);
resolve(result);
},
);

How to send files created in a mobile app without overwritten the name in the server when the app is used by different users

I am working in a mobile app. In this mobile app I need to send a file (.wav file) to a server.
At this moment, I am working locally and testing my app. I am creating an audio file in the mobile app with a defined name and extension. However, I'm wondering, If my app is used by more people,
can it happen that, if the different users use the app and send the file at the same time, as the file name is already defined in the app, in the server this file is going to be overwitten ?
What is usually the behaviour in a situation like this? And if the file is overwitten, how can I overcome this problem, since diffrent users may send a different file?
Details:
API : FAST API :
async def something(file: UploadFile = File(...)):
with open(f"{file.filename}", "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
#saved teh file
developing with React NAtive
Using Expo AV to do the audio
sending the audio using fetch
sending method:
formData.append("file",
uri: path,
name: "audio.wav",
type: "audio/wav",
....
method: "POST",
headers: {
"Content-Type": "multipart/form-data",
},
body: formData,
Thanks !
This scenario should be handled completely by the server. The client should not contain any logic on what files are already located on the server and which are not.
Let the server create a new uuid for each new file that it receives.
Thus, the metadata for a file upload could be the following object.
{
uuid: "11edc52b-2918-4d71-9058-f7285e29d894",
fileUri: "",
}
Thus, the server needs to be adapted to solve this problem. The file is then stored along with its unique identifier. No name clash should occur.
Of course, if you want to display the files in the client later, then you need some name property, which could be the fileUri appended with a counter variable if the same fileUri exists multiple times. This should be handled by the server as well.

How to change the http client used by pouchDB?

I am using PouchDB and CouchDB in an ionic application. While I can successfully sync local and remote databases on Chrome and Android, I get unauthorized error on Safari / iOS when I run the sync command. Below is a simplified version of my database service provider.
import PouchDB from 'pouchdb';
import PouchDBAuthentication from 'pouchdb-authentication';
#Injectable()
export class CouchDbServiceProvider {
private db: any;
private remote: any;
constructor() {
PouchDB.plugin(PouchDBAuthentication);
this.db = new PouchDB('localdb', {skip_setup: true});
}
...
login(credentials) {
let couchDBurl = 'URL of my couchDB database';
this.remote = new PouchDB(couchDBurl);
this.remote.logIn(credentials.username, credentials.password, function (err, response) {
if (err) { concole.log('login error') }
else {
let options = { live: true, retry: true, continuous: true };
this.db.sync(this.remote, options).on('error', (err_) => { console.log('sync error')});
}
})
}
...
}
In the code above, this.remote.logIn(...) is successful but this.db.sync(...) fails. I have checked the requests via the network tab of developer tools and I believe the issue is that the cookie that's retruned in the response header of this.remote.logIn(...) is not used by the subsequent calls (thus the unauthorized error). The issue is fixed once third-party cookies are enabled on Safari, which is not an option on iOS.
How can I fix this problem?
One potential solution I'm considering is overriding fetch to use native http client (i.e., an instance of HTTP from #ionic-native/http). It seems modifying http clients is a possibility (e.g., according to this conversation) but I'm not sure how to achieve that.
Changing the HTTP plumbing sounds like a really bad idea - time cost, mainly - unless you just absolutely have to use sessions/cookies...If you don't, read on.
as noted here regarding pouchDB Security, I tried using pouchdb-authentication when it was actively maintained and went another route due to multiple issues (I don't recall specifics, it was 6 years ago).
Do note the last commit to pouchdb-authentication seems to be 3 years ago. Although inactivity is not an negative indicator on the surface - a project may have simply reached a solid conclusion - installing pouchdb-authentication yields this
found 6 vulnerabilities (2 moderate, 3 high, 1 critical)
That plus the lack of love given to plugin over the last few years makes for a dangerous technical debt to add for a new project.
If possible simply send credentials using the auth option when creating (or opening) a remote database, e.g.
const credentials = { username: 'foo', passwd: 'bar' };
this.remote = new PouchDB(couchDBurl, { auth: credentials });
I don't recall why but I wrote code that is in essence what follows below, and have reused it ad nauseum because it just works with the fetch option
const user = { name: 'foo', pass: 'bar' };
const options = { fetch: function (url, opts) {
opts.headers.set('Authorization', 'Basic ' + window.btoa(user.name+':'+user.pass));
return PouchDB.fetch(url, opts);
}
};
this.remote = new PouchDB(couchDBurl, options);
I believe I chose this approach due to the nature of my authentication workflow discussed in the first link of this answer.
I agree with #RamblinRose that you might have to include the headers manually when you define the PouchDB object.
I myself have found a solution when working with JWTs that need to be included in the header for sync purposes.
See this answer. Note: RxDB uses PouchDB under the hood so it's applicable to this situation. It helped me sync, hope it does you too!
https://stackoverflow.com/a/64503760/5012227
One potential solution I'm considering is overriding fetch to use native http client (i.e., an instance of HTTP from #ionic-native/http). It seems modifying http clients is a possibility (e.g., according to this conversation) but I'm not sure how to achieve that.
Yes, this is a possible option - especially if you want to use SSL pinning which will only work with native requests. And you don't need to worry about CORS (apart from ionic serve).
You can achieve this e.g. by taking an existing fetch - polyfill and modifying it s.t. it uses the http plugin instead of xhr. And since you'll only deal with JSON when interacting with the CouchDB, you can throw away most of the polyfill.

How to upload a dynamically generated Pdf file to api using swift

I'm doing a app which takes input from the user and generates PDF file.i"m trying to upload generated pdf file to api.but, i'm not getting how to do it, i'm totally new to swift.can anyone please give me a exsample on how to upload a file to api
Thanks in advance
First, I'd suggest you consider using Alamofire if you don't want to get lost in the idiosyncrasies of composing network requests. If you do it yourself, it can get pretty hairy (see https://stackoverflow.com/a/26163136/1271826 for example of how to construct multipart/formdata request manually).
Second, in terms of how that request should be formed, it depends entirely upon how you designed the API. But the easiest for file uploads is to support multipart/formdata requests (e.g. in PHP, using the $_FILES mechanism). See http://php.net/manual/en/features.file-upload.php. Or see example here that not only uploads image file (which you can easily modify to accept PDFs), but constructs JSON response, too: https://stackoverflow.com/a/19743872/1271826.
Anyway, if your server is designed to handle multipart/formdata requests, you can create request and parse the response using Alamofire, as shown in the Uploading MultipartFormData section of the README file:
Alamofire.upload(
.POST,
"https://httpbin.org/post",
multipartFormData: { multipartFormData in
multipartFormData.appendBodyPart(fileURL: unicornImageURL, name: "unicorn")
multipartFormData.appendBodyPart(fileURL: rainbowImageURL, name: "rainbow")
},
encodingCompletion: { encodingResult in
switch encodingResult {
case .Success(let upload, _, _):
upload.responseJSON { response in
debugPrint(response)
}
case .Failure(let encodingError):
print(encodingError)
}
}
)

Handling of Thumbnails in Google Drive Android API (GDAA)

I've run into the following problem when porting an app from REST API to GDAA.
The app needs to download some of (thousands of) JPEG images based on user selection. The way this is solved in the app is by downloading a thumbnail version first, using this construct of the REST API:
private static InputStream getCont(String rsid, boolean bBig){
InputStream is = null;
if (rsid != null) try {
File gFl = bBig ?
mGOOSvc.files().get(rsid).setFields("downloadUrl" ).execute():
mGOOSvc.files().get(rsid).setFields("thumbnailLink").execute();
if (gFl != null){
GenericUrl url = new GenericUrl(bBig ? gFl.getDownloadUrl() : gFl.getThumbnailLink());
is = mGOOSvc.getRequestFactory().buildGetRequest(url).execute().getContent();
}
} catch (UserRecoverableAuthIOException uraEx) {
authorize(uraEx.getIntent());
} catch (GoogleAuthIOException gauEx) {}
catch (Exception e) { }
return is;
}
It allows to get either a 'thumbnail' or 'full-blown' version of an image based on the bBig flag. User can select a thumbnail from a list and the full-blown image download follows (all of this supported by disk-base LRU cache, of course).
The problem is, that GDAA does not have an option to ask for reduced size / thumbnail version of an object (AFAIK), so I have to resort to combining both APIs, which makes the code more convoluted then I like (bottom of the page). Needles to state that the 'Resource ID' needed by the REST may not be immediately available.
So, the question is: Is there a way to ask GDAA for a 'thumbnail' version of a document?
Downloading thumbnails isn't currently available in the Drive Android API, and unfortunately I can't give a timeframe to when it will be available. Until that time, the Drive Java Client Library is the best way to get thumbnails on Android.
We'd appreciate if you go ahead and file a feature request against our issue tracker: https://code.google.com/a/google.com/p/apps-api-issues/
That gives requests more visibility to our teams internally, and issues will be marked resolved when we release updates.
Update: I had an error in the discussion of the request fields.
As Ofir says, you can't get thumbnails with the Drive Android API and you can get thumbnails with the Drive Java Client Library. This page has is a really good primer for getting started:
https://developers.google.com/drive/v3/web/quickstart/android
Oddly, I can't get the fields portion of the request to work as it is on that quick start. As I've experienced, you have to request the fields a little differently.
Since you're doing a custom field request you have to be sure to add the other fields you want as well. Here is how I've gotten it to work:
Drive.Files.List request = mService.files()
.list()
.setFields("files/thumbnailLink, files/name, files/mimeType, files/id")
.setQ("Your file param and/or mime query");
FileList files = request.execute();
files.getFiles(); //Each File in the collection will have a valid thumbnailLink
A sample query might be:
"mimeType = 'image/jpeg' or mimeType = 'video/mp4'"
Hope this helps!