Skip to content

Commit

Permalink
Merge branch 'main' into Bernice/AndroidTestEngineJSONFilesUpdate
Browse files Browse the repository at this point in the history
  • Loading branch information
shrshindeMSFT committed Jul 29, 2024
2 parents 08943f5 + 92fc58c commit efc1ed5
Show file tree
Hide file tree
Showing 13 changed files with 267 additions and 10 deletions.
17 changes: 16 additions & 1 deletion apps/teams-test-app/e2e-test-data/video.sharedFrame.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,26 @@
{
"title": "videoEx.sharedFrame.registerForVideoFrame - Success",
"type": "callResponse",
"version": ">2.12.0",
"version": "<=2.25.0",
"boxSelector": "#box_videoExSharedFrameRegisterForVideoFrame1",
"hostSdkVersion": {
"web": "<=4.0.0"
},
"modulesToDisable": ["videoMediaStream"],
"expectedTestAppValue": "Registration attempt has been initiated. If successful, this message will change when it is invoked on video frame received.",
"expectedAlertValue": "sharedFrame.registerForVideoFrame called with config: {\"format\":\"NV12\",\"requireCameraStream\":false,\"audioInferenceModel\":{}}"
},
{
"title": "videoEx.sharedFrame.registerForVideoFrame - Success",
"type": "callResponse",
"version": ">2.25.0",
"boxSelector": "#box_videoExSharedFrameRegisterForVideoFrame1",
"hostSdkVersion": {
"web": ">4.0.0"
},
"modulesToDisable": ["videoMediaStream"],
"expectedTestAppValue": "Registration attempt has been initiated. If successful, this message will change when it is invoked on video frame received.",
"expectedAlertValue": "sharedFrame.registerForVideoFrame called with config: {\"format\":\"NV12\",\"requireCameraStream\":false,\"audioInferenceModel\":{},\"requiredCapabilities\":[]}"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ const MediaStreamRegisterForVideoFrame = (): React.ReactElement =>
onClick: async (setResult) => {
try {
const audioInferenceModel = new ArrayBuffer(8);
const requiredCapabilities = [];
const view = new Uint8Array(audioInferenceModel);
for (let i = 0; i < view.length; i++) {
view[i] = i;
Expand All @@ -121,6 +122,7 @@ const MediaStreamRegisterForVideoFrame = (): React.ReactElement =>
format: videoEffects.VideoFrameFormat.NV12,
requireCameraStream: false,
audioInferenceModel,
requiredCapabilities,
},
});
} catch (error) {
Expand Down Expand Up @@ -169,6 +171,7 @@ const SharedFrameRegisterForVideoFrame = (): React.ReactElement =>
onClick: async (setResult) => {
try {
const audioInferenceModel = new ArrayBuffer(8);
const requiredCapabilities = [];
const view = new Uint8Array(audioInferenceModel);
for (let i = 0; i < view.length; i++) {
view[i] = i;
Expand All @@ -184,6 +187,7 @@ const SharedFrameRegisterForVideoFrame = (): React.ReactElement =>
format: videoEffects.VideoFrameFormat.NV12,
requireCameraStream: false,
audioInferenceModel,
requiredCapabilities,
},
});
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Added support for any `*.cloud.microsoft` domain to be a valid host",
"packageName": "@microsoft/teams-js",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Added in WXP domain for unified store",
"packageName": "@microsoft/teams-js",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Added new fields to `VideoFrameConfig` and `VideoFrameData` to allow specifying additional capabilities to be applied to a video frame and reading arbitrary attributes on a video frame respectively. The capability is still awaiting support in one or most host applications. To track availability of this capability across different hosts see https://aka.ms/capmatrix",
"packageName": "@microsoft/teams-js",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Fixed behavior of the `isValidOriginsCacheEmpty` function whose name was backwards of what it was actually doing",
"packageName": "@microsoft/teams-js",
"email": "[email protected]",
"dependentChangeType": "patch"
}
7 changes: 3 additions & 4 deletions packages/teams-js/src/artifactsForCDN/validDomains.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@
"edgeservices.bing.com",
"www.bing.com",
"www.staging-bing-int.com",
"teams.cloud.microsoft",
"outlook.cloud.microsoft",
"m365.cloud.microsoft",
"*.cloud.microsoft",
"copilot.microsoft.com",
"windows.msn.com",
"fa000000125.resources.office.net",
"fa000000129.resources.office.net",
"fa000000124.resources.office.net",
"fa000000128.resources.office.net"
"fa000000128.resources.office.net",
"fa000000136.resources.office.net"
]
}
4 changes: 2 additions & 2 deletions packages/teams-js/src/internal/validOrigins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ export async function prefetchOriginsFromCDN(): Promise<void> {
}

function isValidOriginsCacheEmpty(): boolean {
return validOriginsCache.length !== 0;
return validOriginsCache.length === 0;
}

async function getValidOriginsListFromCDN(): Promise<string[]> {
if (isValidOriginsCacheEmpty()) {
if (!isValidOriginsCacheEmpty()) {
return validOriginsCache;
}
if (!inServerSideRenderingEnvironment()) {
Expand Down
63 changes: 60 additions & 3 deletions packages/teams-js/src/internal/videoEffectsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ class OneTextureMetadata {
// Stream id for audio inference metadata, which is the 4-byte ASCII string "1dia" hardcoded by the host
// (1dia stands for "audio inference data version 1")
private readonly AUDIO_INFERENCE_RESULT_STREAM_ID = 0x31646961;
private readonly ATTRIBUTE_ID_MAP_STREAM_ID = 0x4d444941;
public constructor(metadataBuffer: ArrayBuffer, streamCount: number) {
const metadataDataView = new Uint32Array(metadataBuffer);
for (let i = 0, index = 0; i < streamCount; i++) {
Expand All @@ -300,6 +301,58 @@ class OneTextureMetadata {
public get audioInferenceResult(): Uint8Array | undefined {
return this.metadataMap.get(this.AUDIO_INFERENCE_RESULT_STREAM_ID);
}

/**
* @hidden
* Additional attributes on the video frame are string-indexed, with their stream Id dynamically generated.
* The mapping of attribute Ids to their stream Ids is itself stored as frame metadata with layout:
*
* | attribute count | attribute stream Id | attribute id | ... |
* | :---: | :---: | :---: | :---: |
* | 4 bytes | 4 bytes | variable length string (null terminated, 4 byte aligned) | ... |
*
*
* @internal
* Limited to Microsoft-internal use
*/
public get attributes(): ReadonlyMap<string, Uint8Array> | undefined {
const data = this.metadataMap.get(this.ATTRIBUTE_ID_MAP_STREAM_ID);
if (data === undefined) {
return undefined;
}

const map: Map<string, Uint8Array> = new Map();
const textDecoder = new TextDecoder('utf-8');

let offset = 0;
const count = data[offset] + (data[++offset] << 8) + (data[++offset] << 16) + (data[++offset] << 24);

for (let i = 0; i < count && offset < data.length - 1; i++) {
const streamId = data[++offset] + (data[++offset] << 8) + (data[++offset] << 16) + (data[++offset] << 24);

// Find start of null-terminator for the subsequent variable-length string entry
const nullTerminatorStartIndex = data.findIndex((value, index, _) => {
return value == 0 && index > offset;
});

const attributeId = textDecoder.decode(data.slice(++offset, nullTerminatorStartIndex));

// Read attribute value from metadata map
const metadata = this.metadataMap.get(streamId);
if (metadata !== undefined) {
map.set(attributeId, metadata);
}

// Variable length attribute Id strings are null-terminated to a 4-byte alignment
const stringByteLength = nullTerminatorStartIndex - offset;
const paddingSize = 4 - (stringByteLength % 4);

// Set offset to index of last trailing zero
offset = nullTerminatorStartIndex + (paddingSize - 1);
}

return map;
}
}

class TransformerWithMetadata {
Expand All @@ -325,9 +378,9 @@ class TransformerWithMetadata {
const timestamp = originalFrame.timestamp;
if (timestamp !== null) {
try {
const { videoFrame, metadata: { audioInferenceResult } = {} } =
const { videoFrame, metadata: { audioInferenceResult, attributes } = {} } =
await this.extractVideoFrameAndMetadata(originalFrame);
const frameProcessedByApp = await this.videoFrameHandler({ videoFrame, audioInferenceResult });
const frameProcessedByApp = await this.videoFrameHandler({ videoFrame, audioInferenceResult, attributes });
// the current typescript version(4.6.4) dosn't support webcodecs API fully, we have to do type conversion here.
const processedFrame = new VideoFrame(frameProcessedByApp as unknown as CanvasImageSource, {
// we need the timestamp to be unchanged from the oirginal frame, so we explicitly set it here.
Expand Down Expand Up @@ -373,7 +426,10 @@ class TransformerWithMetadata {
*/
private extractVideoFrameAndMetadata = async (
texture: VideoFrame,
): Promise<{ videoFrame: VideoFrame; metadata: { audioInferenceResult?: Uint8Array } }> => {
): Promise<{
videoFrame: VideoFrame;
metadata: { audioInferenceResult?: Uint8Array; attributes?: ReadonlyMap<string, Uint8Array> };
}> => {
if (inServerSideRenderingEnvironment()) {
throw errorNotSupportedOnPlatform;
}
Expand Down Expand Up @@ -427,6 +483,7 @@ class TransformerWithMetadata {
}) as VideoFrame,
metadata: {
audioInferenceResult: this.shouldDiscardAudioInferenceResult ? undefined : metadata.audioInferenceResult,
attributes: metadata.attributes,
},
};
};
Expand Down
18 changes: 18 additions & 0 deletions packages/teams-js/src/private/videoEffectsEx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ export namespace videoEffectsEx {
* Limited to Microsoft-internal use
*/
audioInferenceModel?: ArrayBuffer;
/**
* @hidden
* Specifies additional capabilities that should be applied to the video frame
* @beta
*
* @internal
* Limited to Microsoft-internal use
*/
requiredCapabilities?: string[];
}

/**
Expand Down Expand Up @@ -139,6 +148,15 @@ export namespace videoEffectsEx {
* Limited to Microsoft-internal use
*/
audioInferenceResult?: Uint8Array;
/**
* @hidden
* Additional metadata determined by capabilities specified in {@linkcode VideoFrameConfig.requiredCapabilities}
* @beta
*
* @internal
* Limited to Microsoft-internal use
*/
attributes?: ReadonlyMap<string, Uint8Array>;
};

/**
Expand Down
13 changes: 13 additions & 0 deletions packages/teams-js/test/internal/validOrigins.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,19 @@ describe('validOrigins', () => {
GlobalVars.additionalValidOrigins = ['https://*.testdomain.com'];
expect(result).toBe(false);
});
it('validateOrigin returns true for high-profile *.cloud.microsoft origins', async () => {
let messageOrigin = new URL('https://teams.cloud.microsoft');
let result = await validateOrigin(messageOrigin);
expect(result).toBe(true);

messageOrigin = new URL('https://outlook.cloud.microsoft');
result = await validateOrigin(messageOrigin);
expect(result).toBe(true);

messageOrigin = new URL('https://m365.cloud.microsoft');
result = await validateOrigin(messageOrigin);
expect(result).toBe(true);
});
});
describe('testing main validOrigins flow with invalid json object', () => {
let utils: Utils = new Utils();
Expand Down
4 changes: 4 additions & 0 deletions packages/teams-js/test/private/privateAPIs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ describe('AppSDK-privateAPIs', () => {
'https://www.microsoft365.com',
'https://tasks.office.com',
'https://www.example.com',
'https://teams.cloud.microsoft',
'https://outlook.cloud.microsoft',
'https://m365.cloud.microsoft',
'https://anythingbecauseitsawildcard.cloud.microsoft',
];

supportedDomains.forEach((supportedDomain) => {
Expand Down
Loading

0 comments on commit efc1ed5

Please sign in to comment.