I am experiencing a problem when working with CAST web receiver. DRM Video does not start on the TV (Android TV). Preloader works endlessly. How to solve this problem?
The title and description in the player is shown.
The logs show errors:
"shakaErrorCode":6007
LICENSE_REQUEST_FAILED - 6007 - The license request failed. This could be a timeout, a network failure, or a rejection by the server. error.data[0] is a shaka.util.Error from the networking engine. (https://shaka-player-demo.appspot.com/docs/api/shaka.util.Error.html)
"detailedErrorCode":905
LOAD_FAILED - 905 - A load command failed. - Verify the load request is set up properly and the media is able to play. (https://developers.google.com/cast/docs/web_receiver/error_codes?hl=en)
Error 6007 indicates problems with the license server. We checked the request parameters on another player and the DRM video starts. This does not work in cast receiver.
The problem occurs on the physical device
Sender: Redmi Note 8 Pro
Device with chromecast: Android Box
Chromecast built-in: 1.56.276477
CAST SDK CAF Version: 3.0.0103
API Request
Request URL: https://widevine-license.vudrm.tech/proxy
Request Method: POST
Status Code: 200 OK
Remote Address: XXX
Referrer Policy: strict-origin-when-cross-origin
Response Headers
access-control-allow-headers: Content-Type,X-Vudrm-Token
access-control-allow-methods: GET,POST,OPTIONS
access-control-allow-origin: *
Connection: keep-alive
Content-Length: 716
content-type: application/octet-stream
date: Mon, 13 Jun 2022 07:59:00 GMT
server: istio-envoy
x-b3-parentspanid: 3d92950cdf3d42ca
x-b3-sampled: 0
x-b3-spanid: 46ff3c9c3e815372
x-b3-traceid: XXX
x-envoy-upstream-healthchecked-cluster: widevine-license.default
x-envoy-upstream-service-time: 18
x-forwarded-for: XXX,XXX
x-request-id: XXX
x-vudrm: app=widevine-proxy; version=2.4.1
Request Headers
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US
CAST-DEVICE-CAPABILITIES: {"bluetooth_supported":false,"display_supported":true,"hi_res_audio_supported":false,"remote_control_input_supported":false,"touch_input_supported":false}
Connection: keep-alive
Content-Length: 297
content-type: application/json
Host: widevine-license.vudrm.tech
Origin: XXX
Referer: XXX
sec-ch-ua
sec-ch-ua-mobile: ?0
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Linux; Android 9.0; Build/PI) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.225 Safari/537.36 CrKey/1.56.500000
Request Payload
{"token":"XXX","drm_info":[8,4],"contentId":"VS-ADULTSWIM"}
receiver.js
const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();
const playbackConfig = new cast.framework.PlaybackConfig();
const ContentType = {
DASH: 'application/dash+xml',
HLS: 'application/x-mpegurl'
};
const mediaFormatID = {
DASH: 2,
HLS: 4
};
// Debug Logger
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();
const LOG_TAG = 'MyAPP.LOG';
// Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
castDebugLogger.setEnabled(true);
// Set verbosity level for Core events.
castDebugLogger.loggerLevelByEvents = {
'cast.framework.events.category.CORE': cast.framework.LoggerLevel.INFO,
'cast.framework.events.EventType.MEDIA_STATUS': cast.framework.LoggerLevel.DEBUG
};
// Set verbosity level for custom tags.
castDebugLogger.loggerLevelByTags = {
LOG_TAG: cast.framework.LoggerLevel.DEBUG,
};
playerManager.setMessageInterceptor(
cast.framework.messages.MessageType.LOAD,
request => {
return new Promise((resolve, _reject) => {
// Configure player to parse DASH content
if (request.media.metadata.mediaFormatID == mediaFormatID.DASH) {
request.media.contentUrl = request.media.contentUrl;
request.media.contentType = ContentType.DASH;
// Customize the license url for playback
if (request.media.metadata.licenseUrl) {
playbackConfig.licenseUrl = request.media.metadata.licenseUrl;
playbackConfig.protectionSystem = cast.framework.ContentProtection.WIDEVINE;
let token = request.media.metadata.token;
let contentId = request.media.metadata.contentId;
playbackConfig.licenseRequestHandler = requestInfo => {
requestInfo.withCredentials = false;
let body = {
token: token,
drm_info: Array.apply(null, new Uint8Array(requestInfo.content)),
contentId: contentId
};
body = JSON.stringify(body);
requestInfo.content = body;
requestInfo.headers["Content-Type"] = "application/json";
};
}
mpegDashStreamUrl = request.media.contentUrl;
vudrmToken = request.media.metadata.licenseUrl;
} else {
request.media.contentType = ContentType.HLS;
request.media.contentUrl = request.media.contentUrl;
request.media.hlsSegmentFormat = cast.framework.messages.HlsSegmentFormat.FMP4;
request.media.hlsVideoSegmentFormat = cast.framework.messages.HlsVideoSegmentFormat.FMP4;
}
// Add metadata
let metadata = new cast.framework.messages.GenericMediaMetadata();
metadata.title = request.media.metadata.title;
metadata.subtitle = request.media.metadata.subtitle;
request.media.metadata = metadata;
resolve(request);
});
});
context.start({playbackConfig: playbackConfig});
There are 3 handlers that are used by the Shaka response filters -
PlaybackConfig#manifestHandler
PlaybackConfig#licenseHandler
PlaybackConfig#segmentHandler
I added this code and the error was solved:
playbackConfig.licenseHandler = data => {
return new Promise((resolve, _reject) => {
resolve(new Uint8Array(data));
});
};
Related
All of a sudden, I keep getting HTTP 500 errors in my self-hosted ServiceStack WS.
I have several requests already in place and they are working fine, but this one just wont work. I have added my license like this:
private void StartServiceStackService()
{
Licensing.RegisterLicenseFromFileIfExists("servicestack-license.txt".MapHostAbsolutePath());
_serviceStackHost = new ServiceStackWsHost(this, _frontEndModuleParameters, _alfaWebServicesSettings);
_serviceStackHost.Init();
if (!Debugger.IsAttached)
{
_serviceStackHost.Start(new[] { "http://+:8080/" });
}
else
{
_serviceStackHost.Start(new[] { "http://+:8081/" });
}
}
And the failing service is:
[Route(Bookings.BASE_PATH + "search", Verbs = "GET")]
public class SearchAddress : IReturn<SearchAddressResponse>
{
public string SearchString { get; set; }
}
public class SearchAddressResponse : ResponseBase
{
public string Test { get; set; }
// public List<Address> Addresses { get; set; }
}
internal class SearchAddressHandler : ServiceHandlerBase
{
public SearchAddressResponse Get(SearchAddress searchAddress)
{
return new SearchAddressResponse()
{
Test = "ASDASDASD"
};
}
}
And I call it using Fiddler4 like this:
GET http://192.168.0.147:8081/alfaonline/bookings/search?SearchString=123 HTTP/1.1
User-Agent: Fiddler
Host: 192.168.0.147:8081
AuthToken: a18b613c-23b2-4f4e-8934-ad8d6cbc57bb
DeviceUUID: 1baaace
and get this reply:
HTTP/1.1 500 Internal Server Error
Transfer-Encoding: chunked
Content-Type: text/html
Vary: Accept
Server: Microsoft-HTTPAPI/2.0
X-Powered-By: ServiceStack/5.20 Net45/Windows
Date: Wed, 26 Sep 2018 11:28:31 GMT
0
If I instead return "null", like this:
[MyAuthenticate]
internal class SearchAddressHandler : ServiceHandlerBase
{
public SearchAddressResponse Get(SearchAddress searchAddress)
{
return null;
}
}
Fiddler gives me HTTP 204 OK:
HTTP/1.1 204 OK
Content-Length: 0
Vary: Accept
Server: Microsoft-HTTPAPI/2.0
X-Powered-By: ServiceStack/5.20 Net45/Windows
Date: Wed, 26 Sep 2018 11:26:29 GMT
I see no errors, exceptions in VS in debug mode and "catch all" in Exception settings. I can put a breakpoint in the handler, and it breaks there, so the correct handler is executed.
UPDATE I have always been using Fiddler, now running Fiddler4. When I try the service, described below, in for example swagger (plugin to ServiceStack), it runs as expected. If I run the service in Postman, it runs as expected. But if I run it in Fiddler, I get HTTP 500
UPDATE 2 I also just noticed that going to http://127.0.0.1:8081/requestlogs also yields HTTP 500 error. More specifically, when I access /requestlogs and add the UncaughtExceptionHandlers, I see this error:
System.MissingMethodException: Method not found: 'System.String
ServiceStack.StringUtils.HtmlEncodeLite(System.String)'. at
ServiceStack.Formats.HtmlFormat.d__10.MoveNext()
at
System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[TStateMachine](TStateMachine&
stateMachine) at
ServiceStack.Formats.HtmlFormat.SerializeToStreamAsync(IRequest req,
Object response, Stream outputStream) at
ServiceStack.HttpResponseExtensionsInternal.d__7.MoveNext()
Your first approach should be to get information about the Error:
Include a ResponseStatus property in your Response DTO if not already,
Enable Config.DebugMode
Add Debug Logging
Register Exception Handlers.
I am trying to implement Direct Batch send API to send notification. Using Postman to simulate the request. And it returns the Invalid authorization token error.
Post Request :
https://mynamespace.servicebus.windows.net/myHub/messages/$batch?direct&api-version=2015-08
With below Headers:
Content-Type:application/json
Authorization:SharedAccessSignature sr=https://mynamespace.servicebus.windows.net/myHub/messages/$batch?direct%3fapi-version%3d2015-01&sig=xxxx&se=xxxx&skn=DefaultFullSharedAccessSignature
So how to resolved this error?
Also there is a APNS Example :
POST https://{Namespace}.servicebus.windows.net/{Notification Hub}/messages/$batch?direct&api-version=2015-08 HTTP/1.1
Content-Type: multipart/mixed; boundary="simple-boundary"
Authorization: SharedAccessSignature sr=https%3a%2f%2f{Namespace}.servicebus.windows.net%2f{Notification Hub}%2fmessages%2f%24batch%3fdirect%26api-version%3d2015-08&sig={Signature}&skn=DefaultFullSharedAccessSignature
ServiceBusNotification-Format: apple
Host: {Namespace}.servicebus.windows.net
Content-Length: 511
Expect: 100-continue
Connection: Keep-Alive
--simple-boundary
Content-Type: application/json
Content-Disposition: inline; name=notification
{"aps":{"alert":"Hello using APNS via Direct Batch Send!!!"}}
--simple-boundary
Content-Type: application/json
Content-Disposition: inline; name=devices
['Device Token1','Device Token2','Device Token3']
--simple-boundary--
--simple-boundary
Content-Type: application/json
Content-Disposition: inline; name=notification
{"aps":{"alert":"Hello using APNS via Direct Batch Send!!!"}}
--simple-boundary
Content-Type: application/json
Content-Disposition: inline; name=devices
['Device Token1','Device Token2','Device Token3']
--simple-boundary--
How to test it with Postman?
Have you tried to call Direct Batch Send using NotificationHubs SDK? If yes can you compare the http request from SDK with what Postman is sending?
Also the documentation about filling out the Authorization header contains a few inaccuracies. Below C# code shows how to do it the right way.
string GenerateSasToken(Uri uri, string sasKeyName, string sasKeyValue)
{
var targetUri = HttpUtility.UrlEncode(uri.ToString().ToLower(), Encoding.UTF8).ToLower();
var expiresOnDate = Convert.ToInt64(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds) + 60*60 /* one hour */;
var toSign = targetUri + "\n" + expiresOnDate;
var keyBytes = Encoding.UTF8.GetBytes(sasKeyValue);
var mac = new HMACSHA256(keyBytes);
mac.Initialize();
var rawHmac = mac.ComputeHash(Encoding.UTF8.GetBytes(toSign));
var signature = HttpUtility.UrlEncode(Convert.ToBase64String(rawHmac), Encoding.UTF8);
var token = "SharedAccessSignature sr=" + targetUri + "&sig=" + signature + "&se=" + expiresOnDate + "&skn=" + sasKeyName;
return token;
}
Using Apache Http 4.5 MultipartEntityBuilder and can't seem to figure out why the StringBody(String, ContentType) constructor doesn't actually output the Content-Type in the request form body.
public HttpRequestBase build() throws UnsupportedEncodingException {
HttpPost httpPost = new HttpPost("https://{server}/restapi/{apiVersion}/accounts/{accountId}/envelopes");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setContentType(ContentType.MULTIPART_FORM_DATA);
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.setBoundary("AAA");
//add form body
builder.addPart(generateJsonFormBodyPart());
//add file body
builder.addPart(generateFileFormBodyPart()); //<--intentionally omitted
HttpEntity multipart = builder.build();
httpPost.setEntity(multipart);
return httpPost;
}
private FormBodyPart generateJsonFormBodyPart() throws UnsupportedEncodingException{
StringBody json = new StringBody(packageJson(), ContentType.APPLICATION_JSON); //<--THIS DOESN'T SEEM TO WORK
StringBuilder buffer = new StringBuilder();
buffer.append("form-data");
String contentDisposition = buffer.toString();
FormBodyPartBuilder partBuilder = FormBodyPartBuilder.create("application/json", json);
partBuilder.setField(MIME.CONTENT_DISPOSITION, contentDisposition);
FormBodyPart fbp = partBuilder.build();
return fbp;
}
The file portion outputs ok but I get a "Bad Request" return from the peer which I assume is because it has very specific request parameters.
Required Request Output
Accept: application/json
Content-Type: multipart/form-data; boundary=AAA
--AAA
Content-Type: application/json
Content-Disposition: form-data
json removed
--AAA
Content-Type: application/pdf
Content-Disposition: file; filename="test1.pdf";documentid=1
document removed
Actual Apache Http 4.5 Output
X-Docusign-Act-As-User: xyz#company.com
Accept-Encoding: gzip,deflate
User-Agent: Apache-HttpClient/4.5 (Java/1.8.0_65)
Connect-Time: 0
Host: requestb.in
Connection: close
Content-Length: 3178
Authorization: bearer xxxxrandomoauthtokenxxxxx
Content-Type: multipart/form-data; boundary=AAA; charset=ISO-8859-1
Via: 1.1 vegur
X-Request-Id: 89cd1cf5-3615-41e8-84ba-cd076a03af67
Total-Route-Time: 0
--AAA
Content-Disposition: form-data //<--the problem. should be application/json no?
{"status":"created","emailBlurb":"Welcome to Confluence","emailSubject":"Welcome to Confluence","documents":{"name":"Welcome to Confluence.html","documentId":"1","order":"1"},"recipients":{}}
--AAA
Content-Disposition: file; filename="Welcome.html";documentid=1
Content-Type: text/html; charset=ISO-8859-1
h t m l string removed
Q: So why does the ContentType in the StringBody constructor get ignored? Is there a workaround or am I doing it wrong?
I'm convinced this is a bug in Apache Http Mime for the FormBodyPart.build() when processing a StringBody. Evidence from release notes of 4.5.2 indicating bug fixes for other "body" types not outputting "Content-Type" supports this. I will be logging a defect.
The Workaround:
private FormBodyPart generateJsonFormBodyPart() throws UnsupportedEncodingException{
StringBody json = new StringBody(getMyJsonStuff(), ContentType.APPLICATION_JSON); //<--THE GOGGLES, THEY DO NOTHING!!
StringBuilder buffer = new StringBuilder();
buffer.append("form-data");
buffer.append("\r\n");
buffer.append("Content-Type: application/json"); //<--tack this on to the
String kludgeForDispositionAndContentType = buffer.toString();
FormBodyPartBuilder partBuilder = FormBodyPartBuilder.create("stuff", json);
partBuilder.setField(MIME.CONTENT_DISPOSITION, kludgeForDispositionAndContentType);
FormBodyPart fbp = partBuilder.build();
return fbp;
}
Works like a charm.
I've developed a fileupload tool (using nervgh fileupload for angularjs) that works fine in development. The file(s) are send to a WebApi upload controller:
public class UploadController : ApiController
{
public async Task<HttpResponseMessage> PostFormData()
{
// Check if the request contains multipart/form-data.
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath(#"~\" + Properties.Settings.Default.uploadDir);
var provider = new MultipartFormDataStreamProvider(root);
var documentNewDir = "";
var documentRelative = "";
var fileName = "";
try
{
// Read the form data.
await Request.Content.ReadAsMultipartAsync(provider);
// This illustrates how to get the file names.
foreach (MultipartFileData file in provider.FileData)
{
var vergaderDate = Convert.ToDateTime(provider.FormData["vergaderdatum"]);
var jaar = vergaderDate.Year;
var maand= vergaderDate.Month.ToString(CultureInfo.CurrentCulture).PadLeft(2, '0');
var dag =vergaderDate.Day.ToString(CultureInfo.CurrentCulture).PadLeft(2, '0');
//absolute path to documents new dir
documentNewDir = HttpContext.Current.Server.MapPath("/") + Properties.Settings.Default.documentsBaseDir + #"\" + jaar + #"\" + maand + #"\" + dag;
//filename
fileName = file.Headers.ContentDisposition.FileName.Replace("\"", string.Empty);
//relativePath and filename
documentRelative = Properties.Settings.Default.documentsBaseDir + #"/" + jaar + #"/" + maand + #"/" + dag + #"/"+ fileName;
if(!Directory.Exists(documentNewDir))
Directory.CreateDirectory(documentNewDir);
File.Move(file.LocalFileName, documentNewDir + #"\"+fileName);
}
var response = Request.CreateResponse(HttpStatusCode.OK, documentRelative);
return response;
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
This works fine in a development setting but deployed to a MS 2012 server IIS 8.5 production server i get an 404 on the POST API call to api/upload.
The application support some other WebAPI calls that worke fine in both dev/prod environments.... How can i start to investigate/debug this situation?
Here's the call in Fiddler ( left out the filedata....):
-----------------------------7df2b09e0350
Content-Disposition: form-data; name="vergaderdatum"
2015-01-30T00:00:00
-----------------------------7df2b09e0350
Content-Disposition: form-data; name="file"; filename="5.0. Vooraankondiging themabijeenkomstSamen naar Buiten, 17 sept.pdf"
Content-Type: application/pdf
%PDF-1.5
%âãÏÓ
and the response
HTTP/1.1 404 Not Found
Content-Type: text/html
Server: Microsoft-IIS/8.5
X-Powered-By: ASP.NET
Date: Wed, 14 Jan 2015 15:31:08 GMT
Content-Length: 1245
I'VE FOUND THE ERROR!
in production the website was installed as a subdomain of the default website. In the javascript was a reference to the upload method (/api/upload) after i added the name of the subdomain like /bisbeheer/api/upload in the javascript it uploaded the file
i have a SimplaKeyAuthorizeFilter,in the filter,will throw 401
public SimpleKeyAuthorize(IHttpRequest req, IHttpResponse res, object obj, bool isDebugMode){
throw new UnauthorizedAccessException("lack sign info!");
}
in the apphost:
this.ExceptionHandler = (httpReq, httpRes, operationName, ex) =>{
DtoUtils.CreateErrorResponse(httpReq, ex, new ResponseStatus() { ErrorCode = ex.ToErrorCode(), Message = ex.Message });
httpRes.Write(ex.ToErrorCode());
httpRes.EndRequest(skipHeaders:false);
};
........
this.RequestFilters.Add((req,res,obj)=>{
new SimpleKeyAuthorize(req,res,obj,false);
});
but when i call the service,the httpstatuscode is 200,is not 401,why?
HTTP/1.1 200 OK (why not 401?)
Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Fri, 14 Mar 2014 05:56:30 GMT
Content-Length: 27
UnauthorizedAccessException
This is happening because ServiceStack only maps exceptions to status code within the scope of the service.
Request bindings and filters are considered outside this scope, which is why they trigger a separate exception handler method. See the section Customized Error Handling in the Error Handling documentation.
If you throw an exception here you will need to set the response status code yourself.
httpRes.StatusCode = HttpStatusCode.Unauthorized;
Hope this helps.