I have an app streaming music to another phone via Bluetooth. The app decodes mp3 to pcm data and then sends it. The problem is the sound stutters sometimes, but plays ok other times. The play method looks like this:
public void Read()
{
System.Threading.Tasks.Task.Run(() =>
{
int _bufferSize;
AudioTrack _output;
_output = new AudioTrack(Android.Media.Stream.Music, 44100, ChannelOut.Stereo, Android.Media.Encoding.Pcm16bit,
10000, AudioTrackMode.Stream);
_output.Play();
byte[] myReadBuffer = new byte[1000];
//byte[] check = new byte[1];
System.Threading.Tasks.Task.Run(() =>
{
while (true)
{
try
{
mmInStream.Read(myReadBuffer, 0, myReadBuffer.Length);
_output.Write(myReadBuffer, 0, myReadBuffer.Length);
//mmOutStream.Write(check);
}
catch (System.IO.IOException ex)
{
System.Diagnostics.Debug.WriteLine("Input stream was disconnected", ex);
}
}
}).ConfigureAwait(false);
}).ConfigureAwait(false);
}
And after a while it stops and displays this:
02-03 19:08:58.019 W/AudioTrack( 3986): releaseBuffer() track 0xc5e2de00 disabled due to previous underrun, restarting
How would I fix this?
But then I just found out it plays OK when played from my Samsung A5 to better Samsung J7, but then it just stops, here is the log:
02-04 15:44:12.816 W/AudioTrack( 2299): releaseBuffer() track 0xc6fa9380 disabled due to previous underrun, restarting
Thread finished: <Thread Pool> #7
The thread 0x7 has exited with code 0 (0x0).
02-04 15:44:36.239 V/InputMethodManager( 2299): Starting input: tba=android.view.inputmethod.EditorInfo#37c869a nm : com.companyname.sharethemusic ic=null
02-04 15:44:36.239 D/InputMethodManager( 2299): startInputInner - Id : 0
02-04 15:44:36.240 I/InputMethodManager( 2299): startInputInner - mService.startInputOrWindowGainedFocus
02-04 15:44:36.248 D/InputTransport( 2299): Input channel constructed: fd=78
02-04 15:44:36.248 D/InputTransport( 2299): Input channel destroyed: fd=72
02-04 15:44:36.659 D/InputMethodManager( 2299): HSIFW - flag : 0 Pid : 2299
02-04 15:44:36.712 D/BluetoothSocket( 2299): close() this: android.bluetooth.BluetoothSocket#6b2de90, channel: 7, mSocketIS: android.net.LocalSocketImpl$SocketInputStream#c5befa8, mSocketOS: android.net.LocalSocketImpl$SocketOutputStream#a1a6ac1mSocket: android.net.LocalSocket#c0c7266 impl:android.net.LocalSocketImpl#d0bf9a7 fd:java.io.FileDescriptor#2545e54, mSocketState: CONNECTED
02-04 15:44:36.723 D/BluetoothAdapter( 2299): disable()
02-04 15:44:38.062 D/BluetoothAdapter( 2299): onBluetoothStateChange: up=false
02-04 15:44:38.062 D/BluetoothAdapter( 2299): Bluetooth is turned off, stop adv
02-04 15:44:38.063 D/BluetoothAdapter( 2299): There are no active google scan apps, stop scan
02-04 15:44:38.090 D/BluetoothAdapter( 2299): ondisableBLE
02-04 15:44:38.090 D/BluetoothAdapter( 2299): There are no active google scan apps, stop scan
You could improve your code like following .
int buffsize = AudioTrack.GetMinBufferSize(8000, ChannelOut.Mono, Encoding.Pcm16bit);
_output = new AudioTrack(Android.Media.Stream.Music, 8000, ChannelOut.Mono, Android.Media.Encoding.Pcm16bit,
buffsize*4, AudioTrackMode.Stream);
Related
I am trying to access my Firestore database from a MAUI application targeting iOS (using Microsoft tools in an Apple product for Google access; a...peculiar selection of inventory, I know). I am using the NuGet package Google.Cloud.Firestore and trying to initialize an instance of FirebaseDb to access the database but nothing happens. How can I fetch data from a MAUI app targeting iOS? I tried the Xamarin library Plugin.CloudFirestore by f-miyu but cannot make it work in MAUI.
You can see the code below, and more explanations at the end of this question:
public async Task ReadCredentials()
{
System.Diagnostics.Debug.WriteLine("Start reading credentials");
using var stream = await FileSystem.OpenAppPackageFileAsync("FirestoreKey.json");
using StreamReader reader = new(stream);
var contents = reader.ReadToEnd();
System.Diagnostics.Debug.WriteLine("Credentials acquired.");
jsonCredentials = contents;
}
public void InitDb()
{
System.Diagnostics.Debug.WriteLine("Initializing database builder with credentials");
System.Diagnostics.Debug.WriteLine(jsonCredentials);
var dbBuilder = new FirestoreDbBuilder
{
JsonCredentials = jsonCredentials,
WarningLogger = (string message) => System.Diagnostics.Debug.WriteLine(message)
};
System.Diagnostics.Debug.WriteLine("Database builder initialized");
System.Diagnostics.Debug.WriteLine("Building database");
var db = dbBuilder.Build();
System.Diagnostics.Debug.WriteLine("Done");
if (db != null)
System.Diagnostics.Debug.WriteLine("Database built");
else
System.Diagnostics.Debug.WriteLine("FAILED");
}
My plist.info file contains the following lines:
<key>NSAppTransportSecurity</key>
<dict>
<key> NSAllowsArbitraryLoads</key>
<true/>
</dict>
When I run the above methods in order, the application stops at the line building the database and stops without giving me any warning or error info. The remaining lines are not even called. What I get in the console is:
Start reading credentials
Credentials acquired.
Initializing database builder with credentials
{
"type": "service_account",
"project_id": "<removed>",
"private_key_id": "<removed>",
"private_key": "-----BEGIN PRIVATE KEY-----\n<removed>\n",
"client_email": "<removed>",
"client_id": "<removed>",
"auth_uri": "<removed>",
"token_uri": "<removed>",
"auth_provider_x509_cert_url": "<removed>",
"client_x509_cert_url": "<removed>"
}
Database builder initialized
Building database
2022-05-10 12:38:17.827901+0300 istanbul-bridge-conference-maui[2999:97800] SecTaskLoadEntitlements failed error=22 cs_flags=200, pid=2999
2022-05-10 12:38:17.828092+0300 istanbul-bridge-conference-maui[2999:97800] SecTaskCopyDebugDescription: istanbul-bridge-[2999]/0#-1 LF=0
2022-05-10 12:38:17.828353+0300 istanbul-bridge-conference-maui[2999:97800] SecTaskLoadEntitlements failed error=22 cs_flags=200, pid=2999
2022-05-10 12:38:17.828536+0300 istanbul-bridge-conference-maui[2999:97800] SecTaskCopyDebugDescription: istanbul-bridge-[2999]/0#-1 LF=0
Thread started: #14
Thread started: #15
Thread finished: <Thread Pool> #6
Thread finished: <Thread Pool> #13
Thread finished: <Thread Pool> #8
Thread finished: <Thread Pool> #10
Thread finished: <Thread Pool> #12
I am partially following the steps in https://firebase.google.com/docs/firestore/quickstart#c . Since I cannot use the environmental variables in iOS as in the link, I am trying to create FirestoreDb using the json key string. If I do not add NSAllowsArbitraryLoads to the plist file, I get the following console output:
Building database
2022-05-10 11:51:03.397142+0300 istanbul-bridge-conference-maui[2603:74019] SecTaskLoadEntitlements failed error=22 cs_flags=200, pid=2603
2022-05-10 11:51:03.397375+0300 istanbul-bridge-conference-maui[2603:74019] SecTaskCopyDebugDescription: istanbul-bridge-[2603]/0#-1 LF=0
2022-05-10 11:51:03.397657+0300 istanbul-bridge-conference-maui[2603:74019] SecTaskLoadEntitlements failed error=22 cs_flags=200, pid=2603
2022-05-10 11:51:03.397820+0300 istanbul-bridge-conference-maui[2603:74019] SecTaskCopyDebugDescription: istanbul-bridge-[2603]/0#-1 LF=0
2022-05-10 11:51:03.398957+0300 istanbul-bridge-conference-maui[2603:74019] [connection] nw_socket_connect [C1:2] connect failed (fd 13) [65: No route to host]
2022-05-10 11:51:03.399110+0300 istanbul-bridge-conference-maui[2603:74019] [] nw_socket_connect connect failed [65: No route to host]
2022-05-10 11:51:03.399570+0300 istanbul-bridge-conference-maui[2603:74019] Connection 1: received failure notification
2022-05-10 11:51:03.399678+0300 istanbul-bridge-conference-maui[2603:74019] Connection 1: failed to connect 1:65, reason -1
2022-05-10 11:51:03.399767+0300 istanbul-bridge-conference-maui[2603:74019] Connection 1: encountered error(1:65)
2022-05-10 11:51:03.400501+0300 istanbul-bridge-conference-maui[2603:74019] Task <A19F42B0-05EA-46A5-A038-6F385942DB68>.<1> HTTP load failed, 0/0 bytes (error code: -1004 [1:65])
2022-05-10 11:51:03.403258+0300 istanbul-bridge-conference-maui[2603:73954] Task <A19F42B0-05EA-46A5-A038-6F385942DB68>.<1> finished with error [-1004] Error Domain=NSURLErrorDomain Code=-1004 "Could not connect to the server." UserInfo={_kCFStreamErrorCodeKey=65, NSUnderlyingError=0x6000001628b0 {Error Domain=kCFErrorDomainCFNetwork Code=-1004 "(null)" UserInfo={_NSURLErrorNWPathKey=satisfied (Path is satisfied), interface: en0, _kCFStreamErrorCodeKey=65, _kCFStreamErrorDomainKey=1}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <A19F42B0-05EA-46A5-A038-6F385942DB68>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <A19F42B0-05EA-46A5-A038-6F385942DB68>.<1>"
), NSLocalizedDescription=Could not connect to the server., NSErrorFailingURLStringKey=http://169.254.169.254/computeMetadata/v1/?recursive=true, NSErrorFailingURLKey=http://169.254.169.254/computeMetadata/v1/?recursive=true, _kCFStreamErrorDomainKey=1}
I'm making a 3D game on unity, and want to add the energy increasing functionality.
I tried the below code which made my game stuck when trying to test on editor
void Start()
{
// to calculate time since player left app to be used for energy increment
currentTime = DateTime.Now.ToString();
lastTime = PlayerPrefs.GetString("lastTime", currentTime);
if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
{
timeDT = Convert.ToDateTime(currentTime , null);
CurrentTimeDT = Convert.ToDateTime(lastTime, null);
timeSpan = timeDT.Subtract(CurrentTimeDT);
timeDifference = int.Parse(timeSpan.TotalSeconds.ToString());
} else if (Application.platform == RuntimePlatform.WindowsEditor)
{
lastTime = lastTime.Substring(10);
currentTime = currentTime.Substring(10);
timeDT = DateTime.ParseExact(currentTime, "h:mm:ss tt" , null);
CurrentTimeDT = DateTime.ParseExact(lastTime,"h:mm:ss tt", null);
timeSpan = timeDT.Subtract(CurrentTimeDT);
timeDifference = int.Parse(timeSpan.TotalSeconds.ToString());
}
energy = PlayerPrefs.GetInt("energy", 5); //get last saved energy
energy += Mathf.Abs(timeDifference / 300); //add one energy every 5 minutes since the player left app
if (energy > 5) // the maximum energy amount
{
energy = 5;
}
I expected it to increase energy by 1 for each 5 minutes since the player left the game. But I got the unity program stuck with no any outputs. I tried building the game for android I got some logging from logcat.
08-21 04:15:52.153 1747-1760/? I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.Serv4Me.SlidingBall/com.unity3d.player.UnityPlayerActivity bnds=[8,618][149,848]} from uid 1000 on display 0
08-21 04:15:52.153 1747-1760/? V/WindowManager: addAppToken: AppWindowToken{2efb58cd token=Token{24ade64 ActivityRecord{c6b2ff7 u0 com.Serv4Me.SlidingBall/com.unity3d.player.UnityPlayerActivity t39}}} to stack=1 task=39 at 0
08-21 04:15:52.157 2042-2042/? W/ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.sendBroadcast:1341 android.content.ContextWrapper.sendBroadcast:382 com.vphone.launcher.Stats.recordLaunch:129 com.vphone.launcher.Launcher.c:3766 com.vphone.launcher.Launcher.onClickAppShortcut:3718
08-21 04:15:52.161 1747-1770/? V/WindowManager: Adding window Window{28d195fc u0 Starting com.Serv4Me.SlidingBall} at 3 of 6 (after Window{759b336 u0 com.vphone.launcher/com.vphone.launcher.Launcher})
08-21 04:15:52.201 2042-2252/? W/ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.bindService:1770 android.content.ContextWrapper.bindService:539 com.google.android.gms.common.stats.zza.zza:-1 com.google.android.gms.common.stats.zza.zza:-1 com.google.android.gms.ads.identifier.AdvertisingIdClient.zzc:-1
--------- beginning of main
08-21 04:15:52.202 2042-2042/? D/yeshen: launcher onpause
08-21 04:15:52.231 1747-2657/? I/ActivityManager: Start proc 10837:com.Serv4Me.SlidingBall/u0a47 for activity com.Serv4Me.SlidingBall/com.unity3d.player.UnityPlayerActivity
08-21 04:15:52.242 10837-10837/? D/houdini: [10837] Initialize library(version: 5.0.7b_x.48396 RELEASE)... successfully.
08-21 04:15:52.543 10837-10837/? D/houdini: [10837] Added shared library /data/app/com.Serv4Me.SlidingBall-1/lib/arm/libmain.so for ClassLoader by Native Bridge.
08-21 04:15:52.619 1747-2032/? V/WindowManager: Adding window Window{5e10f3d u0 com.Serv4Me.SlidingBall/com.unity3d.player.UnityPlayerActivity} at 3 of 7 (before Window{28d195fc u0 Starting com.Serv4Me.SlidingBall})
08-21 04:15:52.654 1747-1760/? V/WindowManager: Adding window Window{3ef00883 u0 SurfaceView} at 3 of 8 (before Window{5e10f3d u0 com.Serv4Me.SlidingBall/com.unity3d.player.UnityPlayerActivity})
08-21 04:15:52.728 1747-1770/? I/ActivityManager: Displayed com.Serv4Me.SlidingBall/com.unity3d.player.UnityPlayerActivity: +526ms
08-21 04:15:52.728 1747-2034/? W/ContextImpl: Calling a method in the system process without a qualified user: android.app.ContextImpl.sendBroadcast:1327 com.android.server.InputMethodManagerService.hideCurrentInputLocked:1992 com.android.server.InputMethodManagerService.windowGainedFocus:2082 com.android.internal.view.IInputMethodManager$Stub.onTransact:221 com.android.server.InputMethodManagerService.onTransact:873
08-21 04:15:52.738 2042-2042/? D/yeshen: launcher onstop
08-21 04:15:52.738 2042-2042/? D/Tinker.DefaultAppLike: onTrimMemory level:20
08-21 04:15:52.741 2042-2277/? W/DebugConnManager: getNetworkInfo() on networkType 1
08-21 04:15:52.823 10837-10855/? I/Unity: SystemInfo CPU = ARMv7 VFPv3 NEON, Cores = 2, Memory = 2022mb
08-21 04:15:52.823 10837-10855/? I/Unity: SystemInfo ARM big.LITTLE configuration: 2 big (mask: 0x3), 0 little (mask: 0x0)
08-21 04:15:52.825 10837-10855/? I/Unity: ApplicationInfo com.Serv4Me.SlidingBall version 1.0 build 52251d08-2db4-4bc0-b627-11ed2dc44951
08-21 04:15:52.825 10837-10855/? I/Unity: Built from '2019.2/staging' branch, Version '2019.2.1f1 (ca4d5af0be6f)', Build type 'Release', Scripting Backend 'mono', CPU 'armeabi-v7a', Stripping 'Disabled'
08-21 04:15:53.267 10837-10855/? E/EGL_emulation: [eglGetConfigAttrib] Bad attribute idx 12513
08-21 04:15:53.267 10837-10855/? E/EGL_emulation: tid 10855: eglGetConfigAttrib(761): error 0x3004 (EGL_BAD_ATTRIBUTE)
08-21 04:15:53.267 10837-10855/? E/EGL_emulation: [eglGetConfigAttrib] Bad attribute idx 12514
08-21 04:15:53.267 10837-10855/? E/EGL_emulation: tid 10855: eglGetConfigAttrib(761): error 0x3004 (EGL_BAD_ATTRIBUTE)
08-21 04:15:53.267 10837-10855/? E/EGL_emulation: [eglGetConfigAttrib] Bad attribute idx 1
08-21 04:15:53.267 10837-10855/? E/EGL_emulation: tid 10855: eglGetConfigAttrib(761): error 0x3004 (EGL_BAD_ATTRIBUTE)
08-21 04:15:53.307 10837-10855/? D/Unity: GL_EXT_debug_marker GL_OES_EGL_image GL_OES_EGL_image_external GL_OES_depth24 GL_OES_depth32 GL_OES_element_index_uint GL_OES_texture_float GL_OES_texture_float_linear GL_OES_compressed_paletted_texture GL_OES_compressed_ETC1_RGB8_texture GL_OES_depth_texture GL_EXT_texture_format_BGRA8888 GL_APPLE_texture_format_BGRA8888 GL_OES_texture_half_float GL_EXT_robustness GL_OES_texture_half_float_linear GL_OES_packed_depth_stencil GL_OES_vertex_half_float GL_OES_texture_npot GL_OES_rgb8_rgba8 GL_EXT_color_buffer_float ANDROID_gles_max_version_3_1 GL_OES_vertex_array_object
08-21 04:15:54.693 7816-7869/? E/PlayCommon: [290] afxf.d(308): Failed to connect to server for server timestamp: java.net.UnknownHostException: Unable to resolve host "play.googleapis.com": No address associated with hostname
08-21 04:15:54.753 2690-2690/? W/ChimeraUtils: Non Chimera context
08-21 04:15:54.845 7816-7869/? I/PlayCommon: [290] afxf.d(124): Connecting to server: https://play.googleapis.com/play/log?format=raw&proto_v2=true
08-21 04:15:54.847 7816-7869/? E/PlayCommon: [290] afxf.d(287): Failed to connect to server: java.net.UnknownHostException: Unable to resolve host "play.googleapis.com": No address associated with hostname
08-21 04:15:58.283 1747-1817/? D/ConnectivityService: releasing NetworkRequest NetworkRequest [ id=58, legacyType=-1, [ Capabilities: INTERNET&NOT_RESTRICTED&TRUSTED] ]
08-21 04:15:58.290 2042-2344/? D/ConnectivityManager.CallbackHandler: CM callback handler got msg 524296
08-21 04:15:58.902 1747-2032/? W/SensorService: sensor 00000000 already enabled in connection 0xa15fb460 (ignoring)
I solved the problem by deleting the PlayerPrefs from both the editor and android device which has the wrong datetime string parse. hope this helps someone else.
From a Windows C# application we want to run cipher.exe to remove data from unused disk space, in this case the D: drive:
cipher.exe /w:D:\
When done from a Windows command line, the output would be:
To remove as much data as possible, please close all other applications while
running CIPHER /W.
Writing 0x00
...................................................................................................
Writing 0xFF
...................................................................................................
Writing Random Numbers
...................................................................................................
Those lines with dots fill up incrementally over the duration of the cipher procedure. We thought we'd read those dots from a C# application to track the progress and display it on a progress bar. However we noticed that when the stdout is captured or redirected then the order is different:
cipher.exe /w:D:\ > out.txt
Results in a file with the following contents:
To remove as much data as possible, please close all other applications while
running CIPHER /W.
Writing 0x00
Writing 0xFF
Writing Random Numbers
...................................................................................................
...................................................................................................
...................................................................................................
And so when we try to capture that from a C# application, we don't read the dots until the very end of the process. For example when using the following code:
private void RunCipher()
{
using (Process cipherProcess = new Process())
{
try
{
// Cipher does three phases, one with 00s, one with FFs and one with random bits
// We count dots in the output for each phase to track the progress
// The amount of dots per phase is always 99 (independent of the volume size)
// See the end of this file to find the expected output
cipherProcess.StartInfo.FileName = "cipher.exe";
cipherProcess.StartInfo.Arguments = #"/w:D:\";
cipherProcess.StartInfo.RedirectStandardOutput = true;
cipherProcess.StartInfo.RedirectStandardError = true;
cipherProcess.StartInfo.RedirectStandardInput = true;
cipherProcess.StartInfo.UseShellExecute = false;
cipherProcess.StartInfo.CreateNoWindow = true;
cipherProcess.OutputDataReceived += CipherProcess_OutputDataReceived;
cipherProcess.ErrorDataReceived += CipherProcess_ErrorDataReceived;
cipherProcess.Exited += CipherProcess_Exited;
cipherProcess.Start();
cipherProcess.BeginOutputReadLine();
cipherProcess.BeginErrorReadLine();
cipherProcess.WaitForExit();
}
catch
{
Console.WriteLine("Exception occured");
}
}
Console.WriteLine("Fininshed");
}
private void CipherProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("OutputDataReceived: " + e.Data);
}
private void CipherProcess_Exited(object sender, EventArgs e)
{
Console.WriteLine("Exited");
}
private void CipherProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("ErrorDataReceived: " + e.Data);
}
The output of that is:
OutputDataReceived: To remove as much data as possible, please close all other applications while
OutputDataReceived: running CIPHER /W.
OutputDataReceived: Writing 0x00
The thread 0x41ac has exited with code 0 (0x0).
The thread 0x408c has exited with code 0 (0x0).
OutputDataReceived: Writing 0xFF
The thread 0x39e4 has exited with code 0 (0x0).
The thread 0x3e30 has exited with code 0 (0x0).
OutputDataReceived: Writing Random Numbers
The thread 0x34ac has exited with code 0 (0x0).
The thread 0x3960 has exited with code 0 (0x0).
OutputDataReceived: ...................................................................................................
OutputDataReceived: ...................................................................................................
OutputDataReceived: ...................................................................................................
ErrorDataReceived:
OutputDataReceived:
Fininshed
We also tried without OutputDataReceived+BeginOutputReadLine and instead using process.StandardOutput.Read() but it has the same problem: it first reads all three of the 'Writing (..)' output:
private void RunCipher2()
{
using (Process cipherProcess = new Process())
{
try
{
cipherProcess.StartInfo.FileName = "cipher.exe";
cipherProcess.StartInfo.Arguments = #"/w:D:\";
cipherProcess.StartInfo.RedirectStandardOutput = true;
cipherProcess.StartInfo.RedirectStandardError = true;
cipherProcess.StartInfo.RedirectStandardInput = true;
cipherProcess.StartInfo.UseShellExecute = false;
cipherProcess.StartInfo.CreateNoWindow = true;
cipherProcess.Start();
while (!cipherProcess.StandardOutput.EndOfStream)
{
char nextChar = (char)cipherProcess.StandardOutput.Read();
Console.Write(nextChar);
}
cipherProcess.WaitForExit();
}
catch
{
Console.WriteLine("Exception occured");
}
}
Console.WriteLine("Fininshed");
}
And still the output is in order we wouldn't expect:
To remove as much data as possible, please close all other applications while
running CIPHER /W.
Writing 0x00
Writing 0xFF
Writing Random Numbers
...................................................................................................
...................................................................................................
...................................................................................................
Fininshed
We already found this thread, but that solution requires the redirected output to first work: Read Process StandardOutput before New Line Received
What's happening here? Is there a way to make this work? Or to track the progress in another way? Of course we could detect on the 'Writing' messages and report progress in thirds... but it seems like this should be possible :)
Assuming that the "..." comes out incrementally as progress is made, what you need to do is instead of using the DataRecieved event, is capture the StandardOutput stream and actually read it one character at a time. This way you'll see each individual full stop as it's written out. You can then count how many you've had and use that to infer the progress.
Problem:
I'm developing an android app with Xamarin that uses PushSharp. I am using GCM to send messages to the clients so I can update certain things if the app is open. GCM seems to be sending the same message to the same device multiple times.
Logcat:
Thread started: #12
09-17 08:40:34.307 I/PushSharp-GCM(20855): GCM Message Received!
09-17 08:40:34.317 V/GCMBaseIntentService(20855): Releasing Wakelock
09-17 08:40:34.327 V/UpdateSignalReceiver(20855): Message Receieved: *****
Thread finished: #12
The thread 'Unknown' (0xc) has exited with code 0 (0x0).
09-17 08:40:34.787 V/PushHandlerBroadcastReceiver(20855): OnReceive: com.google.android.c2dm.intent.RECEIVE
09-17 08:40:34.787 V/PushHandlerBroadcastReceiver(20855): GCM IntentService Class: rAMP_TabletV1.x5.GCMIntentService
09-17 08:40:34.787 V/GCMBaseIntentService(20855): Acquiring wakelock
Thread started: #13
09-17 08:40:34.807 I/PushSharp-GCM(20855): GCM Message Received!
09-17 08:40:34.817 V/GCMBaseIntentService(20855): Releasing Wakelock
09-17 08:40:34.817 V/UpdateSignalReceiver(20855): Message Receieved: *****
Thread finished: #13
The thread 'Unknown' (0xd) has exited with code 0 (0x0).
09-17 08:40:35.817 V/PushHandlerBroadcastReceiver(20855): OnReceive: com.google.android.c2dm.intent.RECEIVE
09-17 08:40:35.817 V/PushHandlerBroadcastReceiver(20855): GCM IntentService Class: rAMP_TabletV1.x5.GCMIntentService
09-17 08:40:35.817 V/GCMBaseIntentService(20855): Acquiring wakelock
Thread started: #14
09-17 08:40:35.857 I/PushSharp-GCM(20855): GCM Message Received!
09-17 08:40:35.857 V/GCMBaseIntentService(20855): Releasing Wakelock
09-17 08:40:35.867 V/UpdateSignalReceiver(20855): Message Receieved: *****
Thread finished: #14
The thread 'Unknown' (0xe) has exited with code 0 (0x0).
09-17 08:40:36.277 V/PushHandlerBroadcastReceiver(20855): OnReceive: com.google.android.c2dm.intent.RECEIVE
09-17 08:40:36.277 V/PushHandlerBroadcastReceiver(20855): GCM IntentService Class: rAMP_TabletV1.x5.GCMIntentService
09-17 08:40:36.277 V/GCMBaseIntentService(20855): Acquiring wakelock
Thread started: #15
09-17 08:40:36.327 I/PushSharp-GCM(20855): GCM Message Received!
09-17 08:40:36.327 V/GCMBaseIntentService(20855): Releasing Wakelock
09-17 08:40:36.337 V/UpdateSignalReceiver(20855): Message Receieved: *****
Thread finished: #15
The thread 'Unknown' (0xf) has exited with code 0 (0x0).
09-17 08:40:36.717 V/PushHandlerBroadcastReceiver(20855): OnReceive: com.google.android.c2dm.intent.RECEIVE
09-17 08:40:36.717 V/PushHandlerBroadcastReceiver(20855): GCM IntentService Class: rAMP_TabletV1.x5.GCMIntentService
09-17 08:40:36.717 V/GCMBaseIntentService(20855): Acquiring wakelock
Thread started: #16
09-17 08:40:36.747 I/PushSharp-GCM(20855): GCM Message Received!
09-17 08:40:36.757 V/GCMBaseIntentService(20855): Releasing Wakelock
09-17 08:40:36.757 V/UpdateSignalReceiver(20855): Message Receieved: *****
Sending the Message:
Each device is registered and the registration id is stored in a database. I check the version number and the previous registration id to make sure that there are no duplicates, and also make sure I have the correct registration id. (I have double checked to make sure that there are no duplicates in my database)
The update is called from a WCF service, and it will send the messages to all the registered devices. The method is only called once, and AllRegisteredDevices is a distinct list of device ids to send the message to.
foreach (var deviceId in AllRegisteredDevices)
{
var webRequest = WebRequest.Create("https://android.googleapis.com/gcm/send");
webRequest.Method = "post";
webRequest.ContentType = " application/x-www-form-urlencoded;charset=UTF-8";
webRequest.Headers.Add(string.Format("Authorization: key={0}", GoogleAppID));
webRequest.Headers.Add(string.Format("Sender: id={0}", SENDER_ID));
var postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message="
+ value + "®istration_id=" + deviceId + "";
Byte[] bytes = Encoding.UTF8.GetBytes(postData);
webRequest.ContentLength = bytes.Length;
var dataStream = webRequest.GetRequestStream();
dataStream.Write(bytes, 0, bytes.Length);
dataStream.Close();
var webResponse = webRequest.GetResponse();
dataStream = webResponse.GetResponseStream();
var streamReader = new StreamReader(dataStream);
var responseFromServer = streamReader.ReadToEnd();
streamReader.Close();
dataStream.Close();
webResponse.Close();
} // end loop
Receiving The Message:
I have a custom Broadcast Receiver to handle the message, depending on what the value of "message" is. The PushService passes it along to the receiver.
Push Service
protected override void OnMessage(Context context, Intent intent)
{
Log.Info(PushHandlerBroadcastReceiver.TAG, "GCM Message Received!");
string message = intent.Extras.GetString("message");
var theIntent = new Intent(UpdateAction);
theIntent.PutExtra("message", message);
SendOrderedBroadcast(theIntent, null);
} // end OnMessage
UpdateSignalReceiver
[BroadcastReceiver]
[IntentFilter(new string[]{PushHandlerService.UpdateAction}, Priority = (int)IntentFilterPriority.HighPriority)]
public class UpdateSignalReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
MyActivity TheActivity = ((MyActivity )context);
string message = intent.Extras.GetString("message") ?? "";
Log.Verbose("UpdateSignalReceiver", "Message Receieved: " + message);
if (message == "foo")
{
TheActivity.DoSomething();
} // end if
else if (message == "bar")
{
TheActivity.SomethingElse();
} // end else if
else
{
TheActivity.CatchAllMethod();
} // end else
InvokeAbortBroadcast();
} // end on receieve
} // end UpdateSignalReceiver
Environment
Samsung Galaxy Tab 3
Only factory installed apps (no other apps using the same GCM)
Research:
GCM Multiple Notifications -
had to do with maintenance of the registered devices, which in my case they are all unique, no duplicates, and just to be sure, when populating my AllRegisteredDevices in the GCM call, I select distinct.
GCM Duplicated Messages - GCM bug dating back to Feb, 2013. I doubt the bug is still in place, though it is possible.
Question:
Why am I receiving the same message repeatedly, when I'm only sending it once?
I have decided to go with a throttling approach. While this is not perfect in its implementation, the general idea is as follows:
All Messages are given a Unique ID (Guid)
The Broadcast Receiver has a static list of Guids containing the last 20 Message Ids we received and handled
Only do work on messages that have an id not contained in our list, so we know it's a new message to this device.
Limit the List to 20 IDs so it doesn't grow out of control. (20 seems to be more than enough, as repeat messages typically come in 3, sometimes 5 iterations)
[BroadcastReceiver]
[IntentFilter(new string[]{PushHandlerService.UpdateAction}, Priority = (int)IntentFilterPriority.HighPriority)]
public class UpdateSignalReceiver : BroadcastReceiver
{
private static List<Guid> _Last20MessageIds;
public override void OnReceive(Context context, Intent intent)
{
Guid MessageId;
// Pull the MessageId from the intent
String MessageIdString = intent.Extras.GetString("message_id" ?? Guid.Empty.ToString());
Guid.TryParse(MessageIdString, out MessageId);
if (_Last20MessageIds == null)
{
_Last20MessageIds = new List<Guid>();
}
// Make sure we didn't already receive this Message, then do work
if (MessageId != null && MessageId != Guid.Empty && ! _Last20MessageIds.Contains(MessageId))
{
DoSomeWorkWithIntent(intent);
// Add the guid to the message id list
_Last20MessageIds.Insert(0, MessageId);
// Trim the list to the most recent 20
_Last20MessageIds= _Last20MessageIds.Take(20).ToList();
}
InvokeAbortBroadcast();
} // end on receive
} // end UpdateSignalReceiver
I have written the code for Server/Client program in C#. Without using the Thread, it is working fine. If I use Thread, I am getting following error message.
The thread '' (0x9a8) has exited with code 0 (0x0).
Sample code
public class MyServer{
public MyServer (){
...
...
System.Threading.Thread socThread = new System.Threading.Thread(new System.Threading.ThreadStart(receiveSockets));
socThread.Start();
}
private void receiveSockets()
{
try
{
while(true){
IPAddress ipadd = IPAddress.Parse(systemIPAddress);
TcpListener tcp = new TcpListener(ipadd, 8001);
tcp.Start();
Console.WriteLine("Waiting for client in 8001 port no");
Socket socket = tcp.AcceptSocket();
Console.WriteLine("Client address : " + socket.RemoteEndPoint);
System.Threading.Thread socThread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(receiveData));
socThread.Start(socket);
}
}
catch (Exception e)
{
Console.WriteLine("Error in receive Sockets : " + e.Message);
}
}
private void receiveData(object obj)
{
try
{
while(true){
Socket socket = (Socket)obj;
byte[] data = new byte[1000];
int status = socket.Receive(data);
Console.WriteLine("Received 1.");
string content = Encoding.UTF8.GetString(data, 0, 1000);
Console.WriteLine("Received data 1 : " + content);
}
}
catch (Exception e)
{
Console.WriteLine("Error in receive Data : " + e.Message);
}
}
static void Main(string[] args){
MyServer server = new MyServer();
}
Client Program
static void Main(string[] args)
{
TcpClient tcp = new TcpClient();
tcp.Connect("192.168.1.11", 8001);
Stream stream = tcp.GetStream();
String msg = "Testing...";
byte[] content = new byte[msg.Length * sizeof(char)];
System.Buffer.BlockCopy(msg.ToCharArray(), 0, content, 0, content.Length);
stream.Write(content, 0, content.Length);
}
I am getting the following output.
IP Addrress : 192.168.1.11
Waiting for client in 8001 port no
Client address : 192.168.1.11:50140
The thread '' (0x9a8) has exited with code 0 (0x0).
A first chance exception of type 'System.Net.Sockets.SocketException' occurred in System.dll
The thread '' (0x1760) has exited with code 0 (0x0).
Error in receive Data : An existing connection was forcibly closed by the remote host
The program '[1396] Window_Server.vshost.exe: Managed (v4.0.30319)' has exited with code 0 (0x0).
Please help me to fix this issue.
You need to figure out why you are throwing a socket exception. If you read the documentation for Socket.Receive You would see this section:
Note
If you receive a SocketException, use the SocketException.ErrorCode property to obtain the specific error code.
After you have obtained this code, refer to the Windows Sockets
version 2 API error code documentation in the MSDN library for a
detailed description of the error.
Follwing that link shows you how to read the error code:
The ErrorCode property contains the error code that is associated with
the error that caused the exception.
The default constructor for SocketException sets the ErrorCode
property to the last operating system error that occurred. For more
information about socket error codes, see the Windows Sockets version
2 API error code documentation in MSDN.
Which should bring you to the error codes page.
Now depending on your error code, which you have not provided, you can diagnose the network issue.
"The thread '' (0x9a8) has exited with code 0 (0x0)." is not an error. It is simply telling you that a background thread has exited. Zero means the thread ran and exited successfully.
The exception is in receiveData(object obj) as you should be able to tell, given the exception , "Error in receive Data : An existing connection was forcibly closed by the remote host".
If you post the client program you are working with I might be able to help.
The problem is that Main() does not wait for the sockets to be done with their jobs. As soon as it has created the threads, it exists... And the threads are destroyed.
You need to wait for the socket-handling threads by using events of some sort, or by sleeping, from Main() - or from MyServer(), as long as the program exists only when the whole job is done.