`Page 1/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`1
`+++++¬
`…
`¬2
`Copyright (c) 2001 BeComm Corporation¬
`3
`¬4
`Filename:¬
`5
`¬6
` audiosync.c¬
`7
`¬8
`Group Name:¬
`9
`¬10
`¬11
`¬12
`Overview:¬
`13
`¬14
` This bead adjusts the audio stream by either¬
`15
` dropping data, padding data or resampling data¬
`16
` in an effort to make the path render clock match¬
`17
` the path sample clock.¬
`18
`¬19
` This is done by computing the error in ms,¬
`20
` smoothing the error over successive calls to¬
`21
` the handler to reduce the noise in the signal.¬
`22
` A damping factor is applied to correction to¬
`23
` reduce the likelihood of over correction. Note there¬
`24
` is a significant amount of buffering between this¬
`25
` bead and playout which adds latency to the feedback.¬
`26
` Without damping it would be very possible to over¬
`27
` correct and end up cycling.¬
`28
`¬29
` When a correction value has been found the¬
`30
` stream is modified if necessary to¬
`31
` bring the error back into tolerance.¬
`32
`¬33
` If the audio is very early, the packet is duplicated¬
`34
` as necessary to delay it.¬
`35
`¬36
` If the audio is very late, part or all of the packet¬
`37
` is discarded.¬
`38
`¬39
` If the audio is a little early or late, the packet¬
`40
` is resampled to stretch or shrink it.¬
`41
` ¬
`42
`Notes:¬
`43
`¬44
`
`Page 1 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/be…/…/main/audiosync.c
`Page 2/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
` Currently only supports 16-bit audio streams.¬
`45
` Supporting 8-bits would be relatively trivial.¬
`46
`¬47
`Owner:¬
`48
`¬49
` Guy Carpenter (guyc) 28-Sep-2001¬
`50
`¬51
`--------------------------------------------------------------------------
`52
`---*/¬
`…
`¬53
`#define SOS_DEBUG_ZONE "/beads/audiosync"¬
`54
`¬55
`#include <sosstrings.h>¬
`56
`#include <sosmultimedia.h>¬
`57
`¬58
`SOS_SOURCE_VERSION (¬
`59
` "$Id: audiosync.c,v 1.12 2001/10/23 16:53:51 guyc Exp $"¬
`60
`);¬
`61
`¬62
`/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`63
`+++++¬
`…
`Named Constants¬
`64
`--------------------------------------------------------------------------
`65
`---*/¬
`…
`¬66
`/*¬
`67
` * Name of bead¬
`68
` */¬
`69
`static const char BEAD_NAME[] = "audiosync";¬
`70
`¬71
`/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`72
`+++++¬
`…
`Structs¬
`73
`--------------------------------------------------------------------------
`74
`---*/¬
`…
`¬75
`typedef struct {¬
`76
` SOS_UINT32 Size; /* total size we can contain */¬
`77
` SOS_UINT32 Count; /* current number of entries */¬
`78
` SOS_UINT32 Index; /* index of next new value */¬
`79
` SOS_INT32 Sum; /* total of count values */¬
`80
` SOS_INT32 * Value; /* count values */¬
`81
`} SLIDING_AVG;¬
`82
`¬83
`typedef struct {¬
`84
`
`Page 2 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/be…/…/main/audiosync.c
`Page 3/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
` SOS_BOOLEAN ContextReady;¬
`85
` SOS_ISAMPLECLOCK * MasterClock;¬
`86
` SOS_ISAMPLECLOCK * RenderClock;¬
`87
` SOS_IAUDIOCONTEXT * AudioContext;¬
`88
` SLIDING_AVG AvgError;¬
`89
` SOS_BOOLEAN First;¬
`90
`} AUDIOSYNC_CONTEXT;¬
`91
`¬92
`#define EARLY_BAIL_THRESHOLD 5000 /* fail if > N ms early */¬
`93
`#define LATE_BAIL_THRESHOLD 500000 /* fail is < N ms late */¬
`94
`#define EARLY_COPY_THRESHOLD 200 /* duplicate if > N ms early */¬
`95
`#define LATE_DROP_THRESHOLD 200 /* drop if > N ms late */¬
`96
`#define EARLY_RESAMPLE_THRESHOLD 4 /* resample if > N ms early */¬
`97
`#define LATE_RESAMPLE_THRESHOLD 4 /* resample if > N ms late */¬
`98
`¬99
`#define MAX_RESAMPLE_PERCENT 101 /* super-sample up to 1% */¬
`100
`#define MIN_RESAMPLE_PERCENT 99 /* sub-sample up to 1% */¬
`101
`¬
`102
`#define EARLY_THRESHOLD EARLY_RESAMPLE_THRESHOLD¬
`103
`#define LATE_THRESHOLD LATE_RESAMPLE_THRESHOLD¬
`104
`¬
`105
`#define SMOOTH_FACTOR 8 /* use average of last N errors */¬
`106
`¬
`107
`/*¬
`108
` * REVISIT - can this value be determined empirically?¬
`109
` * Could be quite complicated to converge on the smallest¬
`110
` * value that doesn't over-compensate.¬
`111
` */¬
`112
`#define DAMPING_FACTOR 8 /* correction=N/DAMPING_FACTOR */¬
`113
`¬
`114
`/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`115
`+++++¬
`…
`Utility Functions¬
`116
`++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`117
`+++*/¬
`…
`¬
`118
`SOS_UINT32¬
`119
`Scale(¬
`120
` SOS_UINT32 Value,¬
`121
` SOS_UINT32 Numerator,¬
`122
` SOS_UINT32 Denominator¬
`123
`)¬
`124
`{¬
`125
` SOS_UINT32 whole = Value / Denominator;¬
`126
` SOS_UINT32 remain = Value % Denominator;¬
`127
`
`Page 3 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/be…/…/main/audiosync.c
`Page 4/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`128
`…
`129
`130
`131
`132
`133
`…
`134
`135
`…
`136
`137
`138
`139
`140
`141
`142
`143
`144
`145
`146
`147
`148
`149
`150
`151
`152
`153
`154
`155
`156
`157
`158
`159
`160
`161
`162
`163
`164
`165
`166
`167
`168
`169
`
` SOS_UINT32 result = whole * Numerator + remain * Numerator /
`Denominator;¬
` return result;¬
`}¬
`¬
`¬
`/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`+++++¬
`Sliding Average Routines¬
`--------------------------------------------------------------------------
`---*/¬
`static¬
`SOS_STATUS¬
`SlidingAvg_Init(¬
` SLIDING_AVG * Avg,¬
` SOS_UINT32 Size¬
`)¬
`{¬
`// SOS_Debug_StringPrint("SlidingAvg_Init\n");¬
` Avg->Value = SOS_Mem_Alloc(sizeof(SOS_UINT32)*Size);¬
` SOS_memset(Avg->Value, 0, sizeof(SLIDING_AVG));¬
` Avg->Size = Size;¬
` return Avg->Value ? SOS_Success : SOS_ErrorResourceAllocation;¬
`}¬
`¬
`static¬
`void¬
`SlidingAvg_Uninit(¬
` SLIDING_AVG * Avg¬
`)¬
`{¬
` SOS_Mem_Free(Avg->Value);¬
`}¬
` ¬
`¬
`static¬
`SOS_INT32¬
`SlidingAvg_Add(¬
` SLIDING_AVG * Avg,¬
` SOS_INT32 Value¬
`)¬
`{¬
` SOS_DEBUGOUT_DETAIL(¬
` "SlidingAvg_Add gets %ld\n",¬
` Value¬
`
`Page 4 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/be…/…/main/audiosync.c
`Page 5/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`170
`171
`172
`173
`174
`175
`176
`177
`178
`179
`180
`181
`182
`183
`184
`185
`186
`187
`188
`189
`190
`191
`192
`193
`194
`195
`…
`196
`197
`…
`198
`199
`200
`201
`202
`203
`204
`205
`206
`207
`208
`209
`210
`211
`212
`
` );¬
` ¬
` if (Avg->Count==Avg->Size) {¬
` Avg->Sum-=Avg->Value[Avg->Index];¬
` } else {¬
` Avg->Count++;¬
` }¬
` Avg->Value[Avg->Index]=Value;¬
` Avg->Sum+=Value;¬
`¬
` Avg->Index++;¬
` if (Avg->Index==Avg->Size) {¬
` Avg->Index=0;¬
` }¬
`¬
` SOS_DEBUGOUT_DETAIL(¬
` "SlidingAvg_Add returns %ld/%lu=%ld\n",¬
` Avg->Sum,¬
` Avg->Count,¬
` Avg->Sum/(SOS_INT32)Avg->Count¬
` );¬
` return Avg->Sum/(SOS_INT32)Avg->Count;¬
`}¬
`¬
`¬
`/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`+++++¬
`Context Stuff¬
`--------------------------------------------------------------------------
`---*/¬
`¬
`static¬
`void¬
`AudioSync_ContextDestroy(¬
` AUDIOSYNC_CONTEXT * Context¬
`)¬
`{¬
` SOS_DEBUGOUT_FUNC_TRACE("AudioSync_ContextDestroy\n");¬
`¬
` if (Context) {¬
` SlidingAvg_Uninit(&(Context->AvgError));¬
` SOS_Interface_Release(Context->MasterClock);¬
` SOS_Interface_Release(Context->RenderClock);¬
` SOS_Interface_Release(Context->AudioContext);¬
` SOS_Mem_Free(Context);¬
`
`Page 5 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/be…/…/main/audiosync.c
`Page 6/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`213
`214
`215
`216
`217
`218
`219
`220
`221
`222
`223
`224
`225
`226
`227
`228
`229
`230
`231
`232
`233
`234
`235
`236
`…
`237
`238
`…
`239
`240
`241
`242
`243
`244
`245
`246
`247
`248
`249
`250
`251
`252
`253
`254
`255
`
` }¬
`}¬
`¬
`static¬
`AUDIOSYNC_CONTEXT *¬
`AudioSync_ContextCreate(¬
` void¬
`)¬
`{¬
` AUDIOSYNC_CONTEXT *context;¬
`¬
` SOS_DEBUGOUT_FUNC_TRACE("AudioSync_ContextCreate\n");¬
`¬
` context = SOS_Mem_Alloc(sizeof(*context));¬
` if (context) {¬
` SOS_memset(context, 0, sizeof(*context));¬
` SlidingAvg_Init(&(context->AvgError),SMOOTH_FACTOR);¬
`context->First = SOS_True;¬
` }¬
`¬
` return context;¬
`}¬
`¬
`/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`+++++¬
`¬
`++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`+++*/¬
`¬
`static¬
`SOS_STATUS¬
`AudioSync_KeyCreate(¬
` SOS_PATH *Path,¬
` SOS_MESSAGE *Message¬
`)¬
`{¬
` static SOS_UINT32 s_UniqueId = 0;¬
` SOS_REGOBJECT* uniqueSessionKey;¬
` ¬
` SOS_DEBUGOUT_FUNC_TRACE("AudioSync_KeyCreate\n");¬
`¬
` uniqueSessionKey = SOS_UInt32_Create(s_UniqueId++);¬
` SOS_Path_SessionKeySet(Path, uniqueSessionKey);¬
` SOS_RegObject_Release(uniqueSessionKey);¬
`¬
`
`Page 6 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/be…/…/main/audiosync.c
`Page 7/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`256
`257
`258
`259
`260
`261
`262
`263
`264
`265
`266
`267
`268
`269
`270
`271
`272
`273
`274
`275
`276
`277
`278
`279
`280
`281
`282
`283
`284
`285
`286
`287
`288
`289
`290
`291
`292
`293
`294
`295
`296
`297
`298
`299
`300
`
` return SOS_Success;¬
`}¬
`¬
`SOS_STATUS¬
`ContextClockGet(¬
` SOS_PATH * Path,¬
` const char * Name,¬
` SOS_ISAMPLECLOCK ** ISampleClock¬
`)¬
`{¬
` SOS_STATUS status;¬
` SOS_REGOBJECT *object;¬
` SOS_ISAMPLECLOCK *iSampleClock = NULL;¬
` ¬
` SOS_DEBUGOUT_FUNC_TRACE("ContextClockGet\n");¬
`¬
` status = SOS_Path_AttributeGet(¬
` Path,¬
` Name,¬
` &object¬
` );¬
`¬
` SOS_ASSERT_SOFT_ERROR(¬
` SOS_SUCCEEDED(status),¬
` "Clock not found"¬
` );¬
` ¬
` if (SOS_SUCCEEDED(status)) {¬
` status = SOS_RegObject_InterfaceGet(¬
` object,¬
` SOS_ISAMPLECLOCK_ID,¬
` (void**)&iSampleClock¬
` );¬
` SOS_RegObject_Release(object);¬
` }¬
`¬
` if (ISampleClock) {¬
` *ISampleClock = iSampleClock;¬
` } else {¬
` SOS_Interface_Release(iSampleClock);¬
` status = SOS_ErrorParameter;¬
` }¬
`¬
` return status;¬
`}¬
`
`Page 7 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/be…/…/main/audiosync.c
`Page 8/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`301
`302
`303
`304
`305
`306
`307
`308
`309
`310
`311
`312
`313
`314
`315
`316
`317
`318
`319
`320
`321
`322
`323
`324
`325
`326
`327
`328
`329
`330
`331
`332
`333
`334
`335
`336
`337
`338
`339
`340
`341
`342
`343
`344
`345
`
`¬
`¬
`SOS_STATUS¬
`AudioContextGet(¬
` SOS_PATH * Path,¬
` const char * Name,¬
` SOS_IAUDIOCONTEXT ** IAudioContext¬
`)¬
`{¬
` SOS_STATUS status;¬
` SOS_REGOBJECT *contextObject;¬
` SOS_IAUDIOCONTEXT *iAudioContext = NULL;¬
` ¬
` status = SOS_Path_AttributeGet(¬
` Path,¬
` Name,¬
` &contextObject¬
` );¬
`¬
` SOS_ASSERT_SOFT_ERROR(¬
` SOS_SUCCEEDED(status),¬
` "Path context does not contain an audio context"¬
` );¬
` ¬
` if (SOS_SUCCEEDED(status)) {¬
` status = SOS_RegObject_InterfaceGet(¬
` contextObject,¬
` SOS_IAUDIOCONTEXT_ID,¬
` (void**)&iAudioContext¬
` );¬
` ¬
` SOS_ASSERT_SOFT_ERROR(¬
` SOS_SUCCEEDED(status),¬
` "Audio context does not support required interface"¬
` );¬
` ¬
` SOS_RegObject_Release(contextObject);¬
` }¬
`¬
` *IAudioContext = iAudioContext;¬
`¬
` return status;¬
`}¬
`¬
`¬
`
`Page 8 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/be…/…/main/audiosync.c
`Page 9/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`346
`347
`348
`349
`350
`351
`352
`353
`354
`355
`356
`357
`358
`359
`360
`361
`362
`363
`364
`365
`366
`367
`368
`369
`370
`371
`372
`373
`374
`375
`376
`377
`378
`379
`380
`381
`382
`383
`384
`385
`386
`387
`388
`389
`390
`
`¬
`static¬
`SOS_STATUS¬
`AudioSync_ContextPrepare(¬
` AUDIOSYNC_CONTEXT *Context,¬
` SOS_PATH *Path¬
`)¬
`{¬
` SOS_STATUS status;¬
`¬
` SOS_DEBUGOUT_FUNC_TRACE("AudioSync_ContextPrepare\n");¬
`¬
` if (!Context->RenderClock) {¬
` ContextClockGet(¬
` Path,¬
` SOS_RENDERCLOCK_NAME,¬
` &Context->RenderClock¬
` );¬
` }¬
`¬
` if (!Context->MasterClock) {¬
` ContextClockGet(¬
` Path,¬
` SOS_MASTERCLOCK_NAME,¬
` &Context->MasterClock¬
` );¬
` }¬
`¬
` if (!Context->AudioContext) {¬
` AudioContextGet(¬
` Path,¬
` SOS_AUDIOCONTEXT_NAME,¬
` &Context->AudioContext¬
` );¬
` }¬
` ¬
` /*¬
` * Success only if we got all of the components¬
` */¬
` SOS_DEBUGOUT_DETAIL(¬
` "AudioContext %s MasterClock %s RenderClock %s\n",¬
` Context->AudioContext ? "yes" : "no",¬
` Context->MasterClock ? "yes" : "no",¬
` Context->RenderClock ? "yes" : "no"¬
` );¬
`
`Page 9 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 10/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`391
`392
`393
`394
`395
`396
`397
`398
`399
`400
`…
`401
`402
`…
`403
`404
`405
`406
`407
`408
`409
`410
`411
`412
`413
`414
`415
`416
`417
`418
`419
`420
`421
`422
`423
`424
`425
`426
`427
`428
`429
`430
`431
`432
`433
`
` ¬
` status = (¬
` Context->AudioContext &&¬
` Context->MasterClock &&¬
` Context->RenderClock) ? SOS_Success : SOS_Error;¬
` ¬
` return status;¬
`}¬
`¬
`/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`+++++¬
`Adjustment¬
`++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`+++*/¬
`static¬
`SOS_INT32 *¬
`AudioSync_Resample16(¬
` SOS_INT32 * InBuffer,¬
` SOS_UINT32 InCount,¬
` SOS_UINT32 OutCount¬
`)¬
`{¬
` SOS_INT32 * outBuffer = SOS_Mem_Alloc(OutCount * sizeof(SOS_INT32));¬
` SOS_UINT32 i;¬
`¬
` if (outBuffer) {¬
` for (i=0;i<OutCount;i++) {¬
` outBuffer[i]=InBuffer[i*InCount/OutCount];¬
` }¬
` }¬
` return outBuffer;¬
`}¬
`¬
`static¬
`SOS_STATUS¬
`AudioSync_MessageFill(¬
` SOS_MESSAGE* Message,¬
` char Value¬
`)¬
`{¬
` SOS_STATUS status = SOS_Success;¬
` size_t length;¬
` void *buffer;¬
` ¬
` length = SOS_Message_LengthGet(Message);¬
`
`Page 10 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 11/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`434
`435
`436
`437
`438
`439
`440
`441
`442
`443
`444
`445
`446
`447
`448
`449
`450
`451
`452
`453
`454
`455
`456
`457
`458
`459
`460
`461
`462
`463
`464
`465
`466
`467
`468
`469
`470
`471
`472
`473
`474
`475
`476
`477
`478
`
` buffer = SOS_Mem_Alloc(length);¬
` ¬
` if (buffer) {¬
` // REVISIT - doesn't handle 8-bit silence¬
` SOS_memset(buffer, Value, length);¬
` SOS_Message_HeadDataPop(¬
` Message,¬
` length,¬
` NULL,¬
` NULL¬
` );¬
` SOS_Message_HeadDataPush(¬
` Message,¬
` buffer,¬
` length,¬
` SOS_Mem_Free¬
` );¬
` ¬
` } else {¬
` status = SOS_Error;¬
` }¬
`¬
` return status;¬
`}¬
` ¬
` ¬
`¬
`¬
`static¬
`SOS_STATUS¬
`AudioSync_Adjust(¬
` AUDIOSYNC_CONTEXT* Context,¬
` SOS_PATH* Path,¬
` SOS_MESSAGE* Message,¬
` SOS_CLOCK_TICK MasterEpoch,¬
` SOS_CLOCK_TICK RenderEpoch¬
`)¬
`{¬
` SOS_STATUS status = SOS_Success;¬
` SOS_INT32 early = (SOS_INT32)(MasterEpoch-RenderEpoch);¬
` SOS_INT32 avgEarly = SlidingAvg_Add(&(Context->AvgError),early);¬
` SOS_INT32 avgLate = -avgEarly;¬
` SOS_INT32 avgDelta = avgEarly>0 ? avgEarly : -avgEarly;¬
`¬
` SOS_DEBUGOUT_DETAIL(¬
`
`Page 11 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 12/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`479
`480
`481
`482
`483
`484
`485
`486
`487
`488
`489
`490
`491
`492
`493
`494
`495
`496
`497
`498
`499
`500
`501
`502
`503
`504
`505
`506
`507
`508
`509
`510
`511
`512
`513
`514
`515
`516
`517
`518
`519
`520
`521
`522
`523
`
` "AudioSync MasterEpoch=%lu RenderEpoch=%lu\n",¬
` MasterEpoch,¬
` RenderEpoch¬
` );¬
`¬
` /*¬
` * If master epoch > render epoch then we are early and should delay.¬
` */¬
`¬
` SOS_DEBUGOUT_DETAIL(¬
` "AudioSync reports %ld ms %s (avg %ld %s)\n",¬
` early>0 ? early : -early,¬
` early>0 ? "early" : "late",¬
` avgDelta,¬
` avgEarly>0 ? "early" : "late"¬
` );¬
`¬
`¬
` if (avgLate>LATE_BAIL_THRESHOLD) {¬
` status = SOS_Error;¬
` } else if (avgEarly>EARLY_BAIL_THRESHOLD) {¬
` ¬
` Context->AudioContext->Unpack(¬
` Context->AudioContext,¬
` Message¬
` );¬
`¬
` /*¬
` * if it fails to fill the message it¬
` * leaves the message intact, and we return¬
` * the status which causes the message to¬
` * be discarded ultimately (which is fine)¬
` */¬
` status = AudioSync_MessageFill(Message, 0);¬
` ¬
` Context->AudioContext->Pack(¬
` Context->AudioContext,¬
` Message¬
` );¬
` ¬
` } else if (avgEarly>EARLY_THRESHOLD ||¬
` avgLate>LATE_THRESHOLD) {¬
` SOS_AUDIO_FORMAT format;¬
` SOS_UINT32 samples;¬
` SOS_UINT32 bytes;¬
`
`Page 12 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 13/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`524
`525
`526
`527
`528
`529
`530
`531
`532
`533
`534
`535
`536
`537
`538
`539
`540
`541
`542
`543
`544
`545
`546
`547
`548
`549
`550
`551
`552
`553
`554
`555
`556
`557
`558
`559
`560
`561
`562
`563
`564
`565
`566
`567
`568
`
` SOS_UINT32 quantum;¬
` /*¬
` * We are out of tolerance - need to adjust¬
` */¬
`¬
` Context->AudioContext->Unpack(¬
` Context->AudioContext,¬
` Message¬
` );¬
`¬
` Context->AudioContext->FormatGet(¬
` Context->AudioContext,¬
` NULL, /* no message, we've already unpacked it */¬
` &format¬
` );¬
`¬
` SOS_ASSERT_ASSUMPTION(¬
` format.SampleBits==16,¬
` "Currently only supports 16-bit audio resampling"¬
` );¬
`¬
` samples = Scale(avgDelta,format.Frequency,SOS_MSPERSECOND);¬
` samples /= DAMPING_FACTOR; /* dampen attack */¬
` quantum = (format.SampleBits+SOS_BITSPERBYTE-1)/¬
` SOS_BITSPERBYTE * format.Channels;¬
` bytes = samples * quantum;¬
`¬
`¬
`/* SOS_Debug_StringPrint(¬
` "Error is %lu samples, %lu bytes\n",¬
` samples,¬
` bytes¬
` );¬
`*/¬
` ¬
` if (bytes>0) {¬
`¬
` if (avgLate > LATE_DROP_THRESHOLD) {¬
` /*¬
` * Data is very late, drop it¬
` */¬
` SOS_Message_HeadDataPop(¬
` Message,¬
` bytes,¬
` NULL,¬
`
`Page 13 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 14/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`569
`570
`571
`572
`573
`574
`575
`576
`577
`578
`579
`580
`581
`582
`583
`584
`585
`586
`587
`588
`589
`590
`591
`592
`593
`594
`595
`596
`597
`598
`599
`600
`601
`602
`603
`604
`605
`606
`607
`608
`609
`610
`611
`…
`612
`
` NULL¬
` );¬
`¬
` {// REVISIT - try silencing the fragment¬
` AudioSync_MessageFill(Message, 0);¬
` }¬
` } else if (avgEarly > EARLY_COPY_THRESHOLD) {¬
` /*¬
` * Data is very early, duplicate it enough to¬
` * fill the gap.¬
` */¬
` size_t length = SOS_Message_LengthGet(Message);¬
` while (bytes>0) {¬
` SOS_MESSAGE *append;¬
` size_t take = (bytes < length ? bytes : length);¬
` SOS_Message_HeadMessageCopyFrom(¬
` Message,¬
` take,¬
` &append¬
` );¬
` SOS_Message_TailMessagePush(¬
` Message,¬
` append¬
` );¬
` bytes-=take;¬
` }¬
` ¬
` {// REVISIT - try silencing the fragment¬
` AudioSync_MessageFill(Message, 0);¬
` }¬
` ¬
` } else {¬
` /*¬
` * Data is not quite on time, resample the input¬
` * buffer (up to a 1%) towards the correct values.¬
` */¬
`¬
` size_t length = SOS_Message_LengthGet(Message);¬
` size_t inSamples = length / sizeof(SOS_INT32);¬
` size_t outSamples;¬
`¬
` if (avgEarly>0) {¬
` size_t maxOutSamples =
`inSamples*MAX_RESAMPLE_PERCENT/100;¬
` outSamples = samples+inSamples;¬
`
`Page 14 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 15/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`613
`614
`615
`616
`617
`…
`618
`…
`619
`620
`621
`622
`623
`624
`625
`626
`627
`628
`629
`630
`631
`632
`633
`634
`635
`636
`637
`638
`639
`640
`641
`642
`643
`644
`645
`646
`647
`648
`649
`650
`651
`652
`653
`654
`655
`
` if (outSamples>maxOutSamples) {¬
` outSamples=maxOutSamples;¬
` }¬
` } else {¬
` size_t minOutSamples =
`inSamples*MIN_RESAMPLE_PERCENT/100;¬
` outSamples = samples>inSamples ? 0 :
`inSamples-samples;¬
` if (outSamples<minOutSamples) {¬
` outSamples=minOutSamples;¬
` }¬
` }¬
`¬
` SOS_DEBUGOUT_DETAIL(¬
` "inSamples=%ld, outSamples=%lu\n",¬
` inSamples,¬
` outSamples¬
` );¬
` {¬
` SOS_INT32 *inBuffer = SOS_Mem_Alloc(length);¬
` SOS_INT32 *outBuffer;¬
` SOS_Message_HeadDataPop(¬
` Message,¬
` length,¬
` inBuffer,¬
` NULL¬
` );¬
` outBuffer = AudioSync_Resample16(¬
` inBuffer,¬
` inSamples,¬
` outSamples¬
` );¬
` ¬
` SOS_Message_HeadDataPush(¬
` Message,¬
` outBuffer,¬
` outSamples * sizeof(SOS_INT32),¬
` SOS_Mem_Free¬
` );¬
` SOS_Mem_Free(inBuffer);¬
` }¬
` }¬
` ¬
`#if 0¬
` // USE SILENCE TO FILL THE GAP¬
`
`Page 15 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 16/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`656
`657
`658
`659
`660
`661
`662
`…
`663
`664
`665
`666
`667
`668
`669
`670
`671
`672
`673
`674
`675
`676
`677
`678
`679
`680
`681
`682
`683
`684
`685
`686
`687
`688
`…
`689
`690
`…
`691
`692
`693
`694
`695
`696
`697
`
` // No longer used, but¬
` // REVISIT - might be good to start with silence¬
` // for first couple of packets?¬
`¬
` {¬
` void *data = SOS_Mem_Alloc(bytes);¬
`// SOS_Debug_StringPrint("Inserting %ld
`bytes\n",bytes);¬
` SOS_memset(¬
` data,¬
` format.SampleBits>8 ? 0x00 : 0x7F,¬
` bytes¬
` );¬
` SOS_Message_HeadDataPush(¬
` Message,¬
` data,¬
` bytes,¬
` SOS_Mem_Free¬
` );¬
` }¬
`#endif¬
` }¬
` ¬
` Context->AudioContext->Pack(¬
` Context->AudioContext,¬
` Message¬
` );¬
` }¬
`¬
` return status;¬
`}¬
`¬
`¬
`/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`+++++¬
`Bead Definition¬
`--------------------------------------------------------------------------
`---*/¬
`¬
`static¬
`SOS_STATUS¬
`AudioSync_MessageHandler(¬
` SOS_PATH *Path,¬
` SOS_MESSAGE *Message¬
`)¬
`
`Page 16 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 17/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`698
`699
`700
`701
`702
`703
`704
`705
`706
`707
`708
`709
`710
`711
`712
`713
`714
`715
`716
`717
`718
`719
`720
`721
`722
`723
`724
`725
`726
`727
`728
`729
`730
`…
`731
`732
`733
`734
`735
`736
`737
`738
`739
`740
`…
`
`{¬
` SOS_STATUS status = SOS_Success;¬
` AUDIOSYNC_CONTEXT *context;¬
`¬
` SOS_DEBUGOUT_FUNC_TRACE("AudioSync_MessageHandler\n");¬
`¬
` SOS_Path_SessionContextPeek(Path, (void**)&context);¬
`¬
` if (!context->ContextReady) {¬
` status = AudioSync_ContextPrepare(context, Path);¬
` if (SOS_SUCCEEDED(status)) {¬
` context->ContextReady = SOS_True;¬
` }¬
` }¬
`¬
` if (!context->ContextReady) {¬
` SOS_DEBUGOUT_DETAIL("AudioSync context is not ready");¬
` }¬
`¬
` if (context->ContextReady) {¬
` SOS_CLOCK_TICK masterEpoch;¬
` SOS_CLOCK_TICK renderEpoch;¬
` ¬
` if (SOS_SUCCEEDED(context->RenderClock->EpochGet(¬
` context->RenderClock,¬
` &renderEpoch))) {¬
`// SOS_Debug_StringPrint("Now = %lu\n",SOS_Clock_TickGet());¬
`// SOS_Debug_StringPrint("Render epoch = %lu\n",renderEpoch);¬
` ¬
` if (SOS_SUCCEEDED(context->MasterClock->EpochGet(¬
` context->MasterClock,¬
` &masterEpoch))) {¬
`// SOS_Debug_StringPrint("Master epoch =
`%lu\n",masterEpoch);¬
`¬
` status = AudioSync_Adjust(¬
` context,¬
` Path,¬
` Message,¬
` masterEpoch,¬
` renderEpoch¬
` );¬
` } else {¬
` SOS_DEBUGOUT_DETAIL("Master clock %p not
`set\n",context->MasterClock->Interface.Object);¬
`
`Page 17 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 18/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`741
`742
`743
`…
`744
`745
`746
`747
`748
`749
`750
`751
`752
`753
`754
`755
`756
`757
`758
`759
`760
`761
`762
`763
`764
`765
`766
`767
`768
`769
`770
`771
`772
`773
`774
`775
`776
`777
`778
`779
`780
`781
`782
`783
`784
`
` }¬
` } else {¬
` SOS_DEBUGOUT_DETAIL("Render clock %p not
`set\n",context->RenderClock->Interface.Object);¬
` }¬
` }¬
`¬
` if (context->First) {¬
` if (context->AudioContext) {¬
` context->AudioContext->Unpack(¬
` context->AudioContext,¬
` Message¬
` );¬
`¬
` /*¬
` * if it fails to fill the message it¬
` * leaves the message intact, and we return¬
` * the status which causes the message to¬
` * be discarded ultimately (which is fine)¬
` */¬
` status = AudioSync_MessageFill(Message, 0);¬
` ¬
` context->AudioContext->Pack(¬
` context->AudioContext,¬
` Message¬
` );¬
`context->First = SOS_False;¬
` }¬
` }¬
`¬
` if (SOS_SUCCEEDED(status)) {¬
` SOS_Path_MessageSend(Path, Message);¬
` } else {¬
` SOS_Message_Destroy(Message);¬
` }¬
`¬
` return status;¬
`}¬
`¬
`static¬
`SOS_STATUS¬
`AudioSync_PrerollHandler(¬
` SOS_PATH *Path,¬
` SOS_MESSAGE *Message¬
`)¬
`
`Page 18 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 19/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`785
`786
`787
`788
`789
`790
`791
`792
`793
`794
`795
`796
`797
`798
`799
`800
`801
`…
`802
`803
`804
`805
`806
`807
`808
`809
`810
`811
`812
`813
`814
`815
`816
`817
`818
`819
`820
`821
`822
`823
`824
`825
`826
`827
`828
`
`{¬
` SOS_STATUS status = SOS_Success;¬
` AUDIOSYNC_CONTEXT *context;¬
`¬
` SOS_DEBUGOUT_FUNC_TRACE("AudioSync_PrerollHandler\n");¬
`¬
` SOS_Path_SessionContextPeek(Path, (void**)&context);¬
`¬
` if (!context->AudioContext) {¬
` AudioContextGet(¬
` Path,¬
` SOS_AUDIOCONTEXT_NAME,¬
` &context->AudioContext¬
` );¬
` }¬
`¬
` SOS_ASSERT_ASSUMPTION(context->AudioContext, "Didn't find audio
`context");¬
`¬
` if (context->AudioContext) {¬
` if (context->First) {¬
` SOS_AUDIO_FORMAT format;¬
` SOS_UINT32 delay;¬
` SOS_UINT32 bytes;¬
` void *buffer;¬
`¬
` delay = 3000; // ms - REVISIT¬
`¬
` SOS_DEBUGOUT_FUNC_TRACE("Adding SILENCE\n");¬
` ¬
` context->AudioContext->Unpack(¬
` context->AudioContext,¬
` Message¬
` );¬
`¬
` context->AudioContext->FormatGet(¬
` context->AudioContext,¬
` NULL, /* no message, we've already unpacked it */¬
` &format¬
` );¬
` ¬
` bytes = Scale(delay, format.Frequency, SOS_MSPERSECOND);¬
` buffer = SOS_Mem_Alloc(bytes);¬
`¬
` if (buffer) {¬
`
`Page 19 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 20/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`829
`…
`830
`831
`832
`833
`834
`835
`836
`837
`838
`839
`840
`841
`842
`843
`844
`845
`846
`847
`848
`849
`850
`851
`852
`…
`853
`854
`…
`855
`856
`857
`858
`859
`860
`861
`862
`863
`864
`865
`866
`867
`868
`869
`870
`
` unsigned char silence = format.SampleBits <= 8 ? 0x7F :
`0x00;¬
` SOS_memset(buffer, silence, bytes);¬
` SOS_Message_HeadDataPush(¬
` Message,¬
` buffer,¬
` bytes,¬
` SOS_Mem_Free);¬
` }¬
`¬
` context->AudioContext->Pack(¬
` context->AudioContext,¬
` Message¬
` );¬
`¬
` context->First = SOS_False;¬
` }¬
` }¬
`¬
` status = SOS_Path_MessageSend(Path,Message);¬
`¬
` return status;¬
`}¬
`¬
`/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`+++++¬
`Session Setup¬
`++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`+++*/¬
`¬
`static¬
`SOS_STATUS¬
`AudioSync_SessionInit(¬
` SOS_PATH *Path¬
`)¬
`{¬
` SOS_STATUS status = SOS_Success;¬
` AUDIOSYNC_CONTEXT *context = AudioSync_ContextCreate();¬
`¬
` SOS_DEBUGOUT_FUNC_TRACE("AudioSync_SessionInit\n");¬
`¬
` if (context) {¬
` SOS_Path_SessionContextPut(Path, context);¬
` } else {¬
` status = SOS_Error;¬
`
`Page 20 of 23
`
`Implicit Exhibit 2017
`Sonos v. Implicit, IPR2018-0766, -0767
`
`
`
`/Users/implicit/Desktop/Source Code/2001.11.01/b…/…/main/audiosync.c
`Page 21/23
`Saved: 10/23/01, 11:53:51 AM
`Printed for: Implicit
`
`871
`872
`873
`874
`875
`876
`877
`878
`879
`880
`881
`882
`883
`884
`885
`886
`887
`888
`889
`890
`891
`892
`893
`894
`895
`896
`…
`897
`898
`…
`899
`900
`901
`902
`903
`904
`905
`906
`907
`908
`909
`910
`911
`912
`913
`
` }¬
` ¬
` return status;¬
`}¬
`¬
`static¬
`SOS_STATUS¬
`AudioSync_SessionUninit(¬
` SOS_PATH *Path¬
`)¬
`{¬
` SOS_STATUS status = SOS_Success;¬
` AUDIOSYNC_CONTEXT *context;¬
`¬
` SOS_DEBUGOUT_FUNC_TRACE("AudioSync_SessionUninit\n");¬
`¬
` SOS_Path_SessionContextPeek(Path, (void**)&context);¬
`¬
` if (context) {¬
` AudioSync_ContextDestroy(context);¬
` }¬
`¬
` return status;¬
`}¬
`¬
`/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`+++++¬
`Bead Setup¬
`++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
`+++*/¬
`¬
`static¬
`SOS_STATUS¬
`AudioSync_BeadInit(¬
` SOS_BEAD *Bead,¬
` SOS_REGOBJECT *InitContext¬
`)¬
`{¬
` SOS_STATUS status;¬
`¬
` SOS_DEBUGOUT_FUNC_TRAC